import QRCode from "qrcode";
import type { PoolConnection, RowDataPacket } from "mysql2/promise";
import { getPool, query } from "./db";
import { last4, normalizeMobile } from "./aadhaar";
import { sealPassPayload } from "./pass-crypto";
import { safeInfo } from "./safe-log";

export type VisitorInput = {
  aadhaar: string;
  aadhaarHash: string;
  name: string;
  age: number;
  gender: string;
  mobile: string;
  emergencyContact: string;
  state: string;
  city?: string | null;
  district?: string | null;
  pincode?: string | null;
  postOffice?: string | null;
  addressLine1?: string | null;
  addressLine2?: string | null;
  arrivalDate: string;
  transportMode: string;
  stayType: string;
  channel?: string;
  registrationIp?: string | null;
};

export type VisitorRow = {
  id: number;
  pass_no: string;
  aadhaar_hash: string;
  aadhaar_last4: string;
  name: string;
  age: number;
  gender: string;
  mobile: string;
  emergency_contact: string;
  address_line1?: string | null;
  address_line2?: string | null;
  state: string;
  city?: string | null;
  district?: string | null;
  pincode?: string | null;
  post_office?: string | null;
  arrival_date: string | Date;
  transport_mode: string;
  stay_type: string;
  status: string;
  qr_payload: string;
  channel: string;
  registration_ip?: string | null;
  registration_time: Date | string;
};

async function allocatePassNo(conn: PoolConnection): Promise<string> {
  await conn.execute(
    `UPDATE pass_sequence SET next_val = LAST_INSERT_ID(next_val + 1) WHERE id = 1`,
  );
  const [seqRows] = await conn.query<RowDataPacket[]>(
    `SELECT LAST_INSERT_ID() AS n`,
  );
  const seq = Number(seqRows[0].n);
  return `KM2028-${String(seq).padStart(6, "0")}`;
}

export async function createVisitor(input: VisitorInput) {
  const pool = getPool();
  const conn = await pool.getConnection();
  try {
    await conn.beginTransaction();

    const [dup] = await conn.execute<RowDataPacket[]>(
      `SELECT pass_no FROM visitors WHERE aadhaar_hash = ? LIMIT 1`,
      [input.aadhaarHash],
    );
    if (dup.length) {
      await conn.rollback();
      return {
        ok: false as const,
        error: "This Aadhaar is already registered.",
        existingPass: dup[0].pass_no as string,
      };
    }

    const passNo = await allocatePassNo(conn);
    const aadhaarLast4 = last4(input.aadhaar);
    const minimalPayload = {
      pass_no: passNo,
      name: input.name.trim(),
      arrival: input.arrivalDate,
      status: "Approved",
      aadhaar_last4: aadhaarLast4,
    };
    const qrPayload = sealPassPayload(minimalPayload, {
      pass_no: passNo,
      aadhaar_last4: aadhaarLast4,
    });

    await conn.execute(
      `INSERT INTO visitors (
        pass_no, aadhaar_hash, aadhaar_last4, name, age, gender,
        mobile, emergency_contact, address_line1, address_line2,
        state, city, district, pincode, post_office,
        arrival_date, transport_mode, stay_type, status, qr_payload, channel, registration_ip
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'Approved', ?, ?, ?)`,
      [
        passNo,
        input.aadhaarHash,
        aadhaarLast4,
        input.name.trim(),
        input.age,
        input.gender,
        normalizeMobile(input.mobile),
        normalizeMobile(input.emergencyContact),
        input.addressLine1?.trim() || null,
        input.addressLine2?.trim() || null,
        input.state.trim(),
        input.city?.trim() || null,
        input.district?.trim() || null,
        input.pincode?.replace(/\D/g, "").slice(0, 10) || null,
        input.postOffice?.trim() || null,
        input.arrivalDate,
        input.transportMode,
        input.stayType,
        qrPayload,
        input.channel || "website",
        input.registrationIp || null,
      ],
    );

    await conn.commit();

    safeInfo(
      `[NOTIFY] Pass ${passNo} approved for ${input.name} → SMS/WhatsApp to ${input.mobile}`,
    );

    const site = process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000";
    return {
      ok: true as const,
      pass_no: passNo,
      status: "Approved",
      qr_url: `${site}/api/v1/registration/pass/${passNo}/qr`,
      pass_url: `${site}/pass/${passNo}`,
    };
  } catch (e) {
    await conn.rollback();
    throw e;
  } finally {
    conn.release();
  }
}

export async function getVisitorByPass(passNo: string) {
  const rows = await query<VisitorRow[]>(
    `SELECT * FROM visitors WHERE pass_no = :pass_no LIMIT 1`,
    { pass_no: passNo },
  );
  return Array.isArray(rows) ? rows[0] : undefined;
}

export async function generateQrDataUrl(payload: string) {
  return QRCode.toDataURL(payload, {
    errorCorrectionLevel: "M",
    margin: 2,
    width: 320,
    color: { dark: "#0b0e14", light: "#ffffff" },
  });
}

export async function aadhaarExists(aadhaarHash: string) {
  const rows = await query<{ pass_no: string }[]>(
    `SELECT pass_no FROM visitors WHERE aadhaar_hash = :h LIMIT 1`,
    { h: aadhaarHash },
  );
  const list = rows as unknown as { pass_no: string }[];
  return list[0]?.pass_no;
}
