import { sql, type SQLWrapper } from 'drizzle-orm'
import {
  parseFieldDefinitionVersion,
  type FieldDefinitionVersion,
} from './schema.js'

export {
  legacyFieldToFinalDefinition,
  legacyFieldGroupToFinalDefinition,
  materializeLegacyFieldDefinitionVersion,
  referencedFieldDefinitionVersions,
  type FieldDefinitionReference,
} from './definitions-pure.js'

export type FieldDefinitionIntegrityErrorCode = 'definition-not-found' | 'definition-corrupt'

export class FieldDefinitionIntegrityError extends Error {
  override readonly name = 'FieldDefinitionIntegrityError'

  constructor(
    readonly code: FieldDefinitionIntegrityErrorCode,
    readonly groupKey: string,
    readonly revision: number,
    readonly detail: string,
  ) {
    super(`field definition ${code}: ${groupKey}@${revision} — ${detail}`)
  }
}

export function isFieldDefinitionIntegrityError(error: unknown): error is FieldDefinitionIntegrityError {
  if (typeof error !== 'object' || error === null) return false
  const candidate = error as { code?: unknown; groupKey?: unknown; revision?: unknown; detail?: unknown }
  return (
    (candidate.code === 'definition-not-found' || candidate.code === 'definition-corrupt')
    && typeof candidate.groupKey === 'string'
    && typeof candidate.revision === 'number'
    && typeof candidate.detail === 'string'
  )
}

export interface FieldsDefinitionReader { execute(query: SQLWrapper): Promise<unknown> }

interface DefinitionVersionRow extends Record<string, unknown> {
  groupKey: string
  revision: number
  canonicalHash: string
  definition: unknown
  createdAt: Date | string
  origin: string
}

function definitionPayload(value: unknown): unknown {
  if (typeof value !== 'string') return value
  try { return JSON.parse(value) as unknown }
  catch { throw new TypeError('definition payload is not valid JSON') }
}

export async function resolveFieldDefinitionVersion(
  db: FieldsDefinitionReader,
  groupKey: string,
  revision: number,
): Promise<FieldDefinitionVersion> {
  const result = await db.execute(sql`
    SELECT
      group_key AS "groupKey",
      revision,
      canonical_hash AS "canonicalHash",
      definition,
      created_at AS "createdAt",
      origin
    FROM field_definition_versions
    WHERE group_key = ${groupKey} AND revision = ${revision}
    LIMIT 1
  `)
  const rows = Array.isArray(result)
    ? result
    : typeof result === 'object' && result !== null && Array.isArray((result as { rows?: unknown }).rows)
      ? (result as { rows: unknown[] }).rows
      : []
  const row = rows[0] as DefinitionVersionRow | undefined

  if (!row) {
    throw new FieldDefinitionIntegrityError('definition-not-found', groupKey, revision, 'immutable definition version is missing')
  }

  try {
    return await parseFieldDefinitionVersion({
      groupKey: row.groupKey,
      revision: Number(row.revision),
      canonicalHash: row.canonicalHash,
      definition: definitionPayload(row.definition),
      createdAt: row.createdAt,
      origin: row.origin,
    })
  } catch {
    throw new FieldDefinitionIntegrityError('definition-corrupt', groupKey, revision, 'persisted definition bytes do not match their canonical hash')
  }
}
