/**
 * Cross-reference persistence between tickets and IT Glue assets.
 *
 * Three relationship types:
 *   - 'referenced'             — the analyzer cited this asset/doc when
 *                                 analyzing the ticket (from
 *                                 analyzer_analyses.itglue_docs_referenced)
 *   - 'updated'                — a ticket-driven audit produced a write to
 *                                 the asset
 *   - 'should_have_referenced' — a gap text suggests we needed this asset/doc
 *                                 but didn't find it (reserved for future use;
 *                                 not populated automatically yet)
 *
 * Inserts use ON CONFLICT DO NOTHING against the unique index so re-runs and
 * idempotent retries don't pollute the table.
 */

import postgresClient from '@/lib/services/postgres-client';

export type XrefAssetType = 'flexible_asset' | 'configuration' | 'document';
export type XrefRelationship = 'referenced' | 'updated' | 'should_have_referenced';
export type XrefSource = 'analyzer_referenced' | 'audit_write' | 'manual';
export type XrefConfidence = 'high' | 'medium' | 'low' | null;

export interface XrefRow {
  id: string;
  ticketNumber: string;
  analysisId: string | null;
  assetType: XrefAssetType;
  assetId: string;
  relationship: XrefRelationship;
  source: XrefSource;
  confidence: XrefConfidence;
  details: unknown;
  createdAt: string;
}

interface RawXrefRow {
  id: string;
  ticket_number: string;
  analysis_id: string | null;
  asset_type: XrefAssetType;
  asset_id: string;
  relationship: XrefRelationship;
  source: XrefSource;
  confidence: XrefConfidence;
  details: unknown;
  created_at: Date;
}

const XREF_SELECT = `
  id::text                  AS id,
  ticket_number,
  analysis_id::text         AS analysis_id,
  asset_type,
  asset_id::text            AS asset_id,
  relationship, source, confidence,
  details,
  created_at
`;

function rowToXref(r: RawXrefRow): XrefRow {
  return {
    id: r.id,
    ticketNumber: r.ticket_number,
    analysisId: r.analysis_id,
    assetType: r.asset_type,
    assetId: r.asset_id,
    relationship: r.relationship,
    source: r.source,
    confidence: r.confidence,
    details: r.details,
    createdAt: r.created_at.toISOString(),
  };
}

// ─── Inserts ──────────────────────────────────────────────────────────────

interface InsertXrefRowInput {
  ticketNumber: string;
  analysisId: string | null;
  assetType: XrefAssetType;
  assetId: string | number;
  relationship: XrefRelationship;
  source: XrefSource;
  confidence?: XrefConfidence;
  details?: unknown;
}

export async function insertXref(input: InsertXrefRowInput): Promise<void> {
  await postgresClient.query(
    `INSERT INTO itglue_ticket_xrefs
       (ticket_number, analysis_id, asset_type, asset_id,
        relationship, source, confidence, details)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb)
     ON CONFLICT DO NOTHING`,
    [
      input.ticketNumber,
      input.analysisId,
      input.assetType,
      input.assetId,
      input.relationship,
      input.source,
      input.confidence ?? null,
      JSON.stringify(input.details ?? null),
    ]
  );
}

/**
 * Bulk-insert xref rows from an analyzer_analyses.itglue_docs_referenced
 * payload. Each entry is an ITGlueDocReference: { id, name, url, doc_type,
 * relevance_reason }. We map doc_type → xref asset_type.
 */
export interface AnalyzerDocReference {
  id: string;
  name?: string | null;
  url?: string | null;
  doc_type?: string | null;
  relevance_reason?: string | null;
}

function mapDocTypeToAssetType(docType: string | null | undefined): XrefAssetType | null {
  if (!docType) return null;
  const t = docType.toLowerCase();
  if (t === 'flexible_asset' || t === 'flexible-asset' || t === 'flex_asset') return 'flexible_asset';
  if (t === 'configuration') return 'configuration';
  if (t === 'document') return 'document';
  return null;
}

export async function insertReferencedXrefsFromAnalysis(input: {
  ticketNumber: string;
  analysisId: string;
  references: AnalyzerDocReference[];
}): Promise<{ inserted: number; skipped: number }> {
  let inserted = 0;
  let skipped = 0;
  for (const ref of input.references) {
    const assetType = mapDocTypeToAssetType(ref.doc_type ?? null);
    if (!assetType) {
      skipped += 1;
      continue;
    }
    const numericId = Number(ref.id);
    if (!Number.isFinite(numericId)) {
      skipped += 1;
      continue;
    }
    await insertXref({
      ticketNumber: input.ticketNumber,
      analysisId: input.analysisId,
      assetType,
      assetId: numericId,
      relationship: 'referenced',
      source: 'analyzer_referenced',
      confidence: 'high',
      details: {
        name: ref.name ?? null,
        url: ref.url ?? null,
        relevance_reason: ref.relevance_reason ?? null,
      },
    });
    inserted += 1;
  }
  return { inserted, skipped };
}

export async function insertUpdatedXref(input: {
  ticketNumber: string;
  analysisId: string | null;
  assetType: 'flexible_asset' | 'configuration';
  assetId: string | number;
  writeId: string;
  fieldName: string;
}): Promise<void> {
  await insertXref({
    ticketNumber: input.ticketNumber,
    analysisId: input.analysisId,
    assetType: input.assetType,
    assetId: input.assetId,
    relationship: 'updated',
    source: 'audit_write',
    confidence: 'high',
    details: {
      write_id: input.writeId,
      field_name: input.fieldName,
    },
  });
}

// ─── Queries ──────────────────────────────────────────────────────────────

export async function listXrefsForAsset(
  assetType: 'flexible_asset' | 'configuration',
  assetId: string | number,
  limit = 100
): Promise<XrefRow[]> {
  const res = await postgresClient.query<RawXrefRow>(
    `SELECT ${XREF_SELECT}
       FROM itglue_ticket_xrefs
      WHERE asset_type = $1 AND asset_id = $2
      ORDER BY created_at DESC
      LIMIT $3`,
    [assetType, assetId, limit]
  );
  return res.rows.map(rowToXref);
}

export async function listXrefsForTicket(
  ticketNumber: string,
  limit = 100
): Promise<XrefRow[]> {
  const res = await postgresClient.query<RawXrefRow>(
    `SELECT ${XREF_SELECT}
       FROM itglue_ticket_xrefs
      WHERE ticket_number = $1
      ORDER BY created_at DESC
      LIMIT $2`,
    [ticketNumber, limit]
  );
  return res.rows.map(rowToXref);
}
