import { query } from "../../db/pool.js";

export interface LegalDocumentRow {
  id: number;
  code: string;
  version: string;
  title: string;
  content_markdown: string;
  effective_at: string;
  requires_acceptance: boolean;
  requires_reacceptance: boolean;
  published_at: string;
  created_at: string;
}

export interface LegalAcceptanceRow {
  id: number;
  user_id: number;
  legal_document_id: number;
  accepted_at: string;
  source: string;
  locale: string;
  ip_address: string | null;
  user_agent: string;
  checkbox_text: string;
  created_at: string;
}

const DEFAULT_DOCUMENTS: Array<Omit<LegalDocumentRow, "id" | "effective_at" | "published_at" | "created_at">> = [
  {
    code: "terms_of_use",
    version: "1.0",
    title: "Condiciones de uso",
    content_markdown: "# Condiciones de uso\n\nPendiente de redactar.",
    requires_acceptance: true,
    requires_reacceptance: true,
  },
  {
    code: "privacy_policy",
    version: "1.0",
    title: "Politica de privacidad",
    content_markdown: "# Politica de privacidad\n\nPendiente de redactar.",
    requires_acceptance: true,
    requires_reacceptance: true,
  },
  {
    code: "cookies_policy",
    version: "1.0",
    title: "Politica de cookies",
    content_markdown: "# Politica de cookies\n\nPendiente de redactar.",
    requires_acceptance: false,
    requires_reacceptance: false,
  },
  {
    code: "legal_notice",
    version: "1.0",
    title: "Aviso legal",
    content_markdown: "# Aviso legal\n\nPendiente de redactar.",
    requires_acceptance: false,
    requires_reacceptance: false,
  },
];

export async function seedDefaultLegalDocuments(): Promise<void> {
  for (const doc of DEFAULT_DOCUMENTS) {
    await query(
      `INSERT INTO legal_documents (
         code, version, title, content_markdown,
         requires_acceptance, requires_reacceptance
       ) VALUES ($1, $2, $3, $4, $5, $6)
       ON CONFLICT (code, version) DO NOTHING`,
      [doc.code, doc.version, doc.title, doc.content_markdown, doc.requires_acceptance, doc.requires_reacceptance]
    );
  }
}

export async function listLegalDocuments(): Promise<LegalDocumentRow[]> {
  await seedDefaultLegalDocuments();
  return query<LegalDocumentRow>(
    `SELECT *
     FROM legal_documents
     ORDER BY code ASC, published_at DESC, id DESC`
  );
}

export async function getLatestLegalDocument(code: string): Promise<LegalDocumentRow | null> {
  await seedDefaultLegalDocuments();
  const rows = await query<LegalDocumentRow>(
    `SELECT *
     FROM legal_documents
     WHERE code = $1
     ORDER BY published_at DESC, id DESC
     LIMIT 1`,
    [code]
  );
  return rows[0] ?? null;
}

export async function acceptLegalDocument(input: {
  userId: number;
  code: string;
  version?: string;
  source?: string;
  locale?: string;
  ipAddress?: string | null;
  userAgent?: string;
  checkboxText?: string;
}): Promise<LegalAcceptanceRow | null> {
  const document = input.version
    ? (await query<LegalDocumentRow>(
        `SELECT *
         FROM legal_documents
         WHERE code = $1 AND version = $2
         LIMIT 1`,
        [input.code, input.version]
      ))[0] ?? null
    : await getLatestLegalDocument(input.code);

  if (!document) return null;

  const rows = await query<LegalAcceptanceRow>(
    `INSERT INTO legal_acceptances (
       user_id, legal_document_id, source, locale, ip_address, user_agent, checkbox_text
     ) VALUES ($1, $2, $3, $4, $5::inet, $6, $7)
     ON CONFLICT (user_id, legal_document_id) DO UPDATE SET
       accepted_at = NOW(),
       source = EXCLUDED.source,
       locale = EXCLUDED.locale,
       ip_address = EXCLUDED.ip_address,
       user_agent = EXCLUDED.user_agent,
       checkbox_text = EXCLUDED.checkbox_text
     RETURNING *`,
    [
      input.userId,
      document.id,
      input.source ?? "register",
      input.locale ?? "es",
      input.ipAddress ?? null,
      input.userAgent ?? "",
      input.checkboxText ?? "",
    ]
  );

  return rows[0] ?? null;
}

export async function acceptLegalDocumentsBundle(input: {
  userId: number;
  codes: string[];
  versionByCode?: Record<string, string | undefined>;
  source?: string;
  locale?: string;
  ipAddress?: string | null;
  userAgent?: string;
  checkboxTextByCode?: Record<string, string | undefined>;
}): Promise<LegalAcceptanceRow[]> {
  const accepted: LegalAcceptanceRow[] = [];
  for (const code of input.codes) {
    const row = await acceptLegalDocument({
      userId: input.userId,
      code,
      version: input.versionByCode?.[code],
      source: input.source,
      locale: input.locale,
      ipAddress: input.ipAddress,
      userAgent: input.userAgent,
      checkboxText: input.checkboxTextByCode?.[code],
    });
    if (row) accepted.push(row);
  }
  return accepted;
}

export async function getUserLegalAcceptances(userId: number): Promise<Array<LegalAcceptanceRow & { code: string; version: string; title: string }>> {
  return query<LegalAcceptanceRow & { code: string; version: string; title: string }>(
    `SELECT
       a.*,
       d.code,
       d.version,
       d.title
     FROM legal_acceptances a
     INNER JOIN legal_documents d ON d.id = a.legal_document_id
     WHERE a.user_id = $1
     ORDER BY a.accepted_at DESC`,
    [userId]
  );
}
