import 'server-only'

import { createAdminClient } from '@/lib/supabase/admin'
import { isMissingColumn } from '@/lib/db-compat'
import { getSignedS3Url } from '@/lib/storage/s3'

/**
 * Where a document's file lives, and a URL a browser can open (2026-09-14).
 *
 * Until now every document was a path in the private `trip-documents`
 * bucket, signed at read time. Historical imports add a second case: the
 * provider still hosts the file (documents.storage_provider = 'external',
 * documents.external_url) — Nash: "if we are getting the direct link of
 * documents from Synchron Permits, why save those documents in our S3…
 * but still we will add AWS S3 very soon". This is the ONE place that knows
 * the difference, so adding our own S3 bucket later is a third branch here
 * and nowhere else.
 *
 * Tolerates migration 0017 not being applied: without the new columns every
 * row is a bucket path, exactly as before.
 */

export interface DocumentLocation {
  id: string
  storage_path: string | null
  storage_provider?: 'supabase' | 's3' | 'external' | null
  external_url?: string | null
}

const BUCKET = 'trip-documents'
export const DEFAULT_TTL_SECONDS = 60 * 30

/** URL for one document, or null when it cannot be produced. */
export async function resolveDocumentUrl(
  doc: DocumentLocation,
  ttlSeconds = DEFAULT_TTL_SECONDS,
): Promise<string | null> {
  if (doc.storage_provider === 'external' || (!doc.storage_path && doc.external_url)) {
    return doc.external_url ?? null
  }
  if (!doc.storage_path) return null
  if (doc.storage_provider === 's3') {
    try {
      return await getSignedS3Url(doc.storage_path, ttlSeconds)
    } catch {
      return null
    }
  }
  const admin = createAdminClient()
  const { data } = await admin.storage.from(BUCKET).createSignedUrl(doc.storage_path, ttlSeconds)
  return data?.signedUrl ?? null
}

/** URLs for many documents, keyed by document id. Rows without a URL are absent. */
export async function resolveDocumentUrls(
  docs: DocumentLocation[],
  ttlSeconds = DEFAULT_TTL_SECONDS,
): Promise<Record<string, string>> {
  const urls: Record<string, string> = {}
  await Promise.all(
    docs.map(async (d) => {
      const url = await resolveDocumentUrl(d, ttlSeconds)
      if (url) urls[d.id] = url
    }),
  )
  return urls
}

/**
 * Load the location columns for a set of document ids. Falls back to the
 * pre-0017 column set when the new ones are missing.
 */
export async function loadDocumentLocations(docIds: string[]): Promise<DocumentLocation[]> {
  const ids = [...new Set(docIds.filter(Boolean))]
  if (ids.length === 0) return []
  const admin = createAdminClient()
  const wide = await admin
    .from('documents')
    .select('id, storage_path, storage_provider, external_url')
    .in('id', ids)
  if (!wide.error) return (wide.data ?? []) as DocumentLocation[]
  if (!isMissingColumn(wide.error, 'storage_provider', 'external_url')) return []
  const narrow = await admin.from('documents').select('id, storage_path').in('id', ids)
  return (narrow.data ?? []) as DocumentLocation[]
}
