// pages/api/policies/import.js
import prisma from "@/lib/prisma";

/**
 * Auth:
 * Authorization: Bearer <NEXT_PUBLIC_SECRET_TOKEN>
 */

function assertAuth(req, res) {
  const secret = process.env.NEXT_PUBLIC_SECRET_TOKEN;
  const header = req.headers.authorization || "";
  if (!secret || header !== `Bearer ${secret}`) {
    res.status(401).json({ success: false, message: "Unauthorized" });
    return false;
  }
  return true;
}

function isValidDate(d) {
  return d instanceof Date && !Number.isNaN(d.getTime());
}

function toDateOrNull(v) {
  if (!v) return null;
  const d = new Date(v);
  return isValidDate(d) ? d : null;
}

// Prisma Decimal best practice: send as string
function toDecimalString(v) {
  if (v === null || v === undefined || v === "") return null;
  const n = Number(v);
  if (!Number.isFinite(n)) return null;
  return n.toFixed(2);
}

function toIntOrNull(v) {
  if (v === null || v === undefined || v === "") return null;
  const n = Number(v);
  return Number.isFinite(n) ? n : null;
}

export default async function handler(req, res) {
  if (!assertAuth(req, res)) return;

  if (req.method !== "POST") {
    return res.status(405).json({ success: false, message: "Method Not Allowed" });
  }

  try {
    const policies = req.body?.policies;
    if (!Array.isArray(policies) || policies.length === 0) {
      return res.status(400).json({ success: false, message: "policies array is required" });
    }

    // Validate + normalize
    const errors = [];
    const clean = [];

    for (let i = 0; i < policies.length; i++) {
      const p = policies[i] || {};

      const agency = String(p.agency || "").trim();
      const insured = String(p.insured || "").trim();
      const policyEndorsementNo = String(p.policyEndorsementNo || "").trim();
      const product = String(p.product || "").trim();
      const plate = String(p.plate || "").trim();

      const assignments = String(p.assignments ?? "").trim(); // required in schema
      const paymentStatus = String(p.paymentStatus ?? "").trim(); // required in schema

      const startdate = toDateOrNull(p.startdate);
      const enddate = toDateOrNull(p.enddate);

      const premium = toDecimalString(p.premium);

      // Required checks (schema has non-null)
      if (!agency || !insured || !policyEndorsementNo || !product || !plate) {
        errors.push({ row: i + 2, message: "Missing required text fields" }); // +2 (header + 1-based)
        continue;
      }
      if (!startdate || !enddate) {
        errors.push({ row: i + 2, message: "startdate/enddate missing or invalid" });
        continue;
      }
      if (premium === null) {
        errors.push({ row: i + 2, message: "premium missing or invalid" });
        continue;
      }

      clean.push({
        agency,
        startdate,
        enddate,
        insured,
        policyEndorsementNo,
        product,
        plate,
        premium,

        assignments: assignments || "-", // keep non-empty
        paymentStatus: paymentStatus || "-", // keep non-empty

        grossPremium: toDecimalString(p.grossPremium),
        paidAmount: toDecimalString(p.paidAmount),
        vGecen: toDecimalString(p.vGecen),
        remainingAmount: toDecimalString(p.remainingAmount),

        netPremium: toDecimalString(p.netPremium),
        commission: toDecimalString(p.commission),
        branch: p.branch ? String(p.branch).trim() : null,
        representative: p.representative ? String(p.representative).trim() : null,
        policyStatus: p.policyStatus ? String(p.policyStatus).trim() : null,
        renewed: typeof p.renewed === "boolean" ? p.renewed : p.renewed == null ? null : Boolean(p.renewed),

        brand: p.brand ? String(p.brand).trim() : null,
        brandType: p.brandType ? String(p.brandType).trim() : null,
        modelYear: toIntOrNull(p.modelYear),
        motorNo: p.motorNo ? String(p.motorNo).trim() : null,
        chassisNo: p.chassisNo ? String(p.chassisNo).trim() : null,
        vehicleValue: toIntOrNull(p.vehicleValue),
        usageType: p.usageType ? String(p.usageType).trim() : null,
        licenseSerialNo: p.licenseSerialNo ? String(p.licenseSerialNo).trim() : null,
        inspectionDate: p.inspectionDate ? toDateOrNull(p.inspectionDate) : null,
        productCode: p.productCode ? String(p.productCode).trim() : null,
        phone: p.phone ? String(p.phone).trim() : null,
        nationalId: p.nationalId ? String(p.nationalId).trim() : null,
        birthDate: p.birthDate ? toDateOrNull(p.birthDate) : null,
      });
    }

    // Find existing by policyEndorsementNo
    const keys = [...new Set(clean.map((p) => p.policyEndorsementNo))];
    const existing = await prisma.policy.findMany({
      where: { policyEndorsementNo: { in: keys } },
      select: { id: true, policyEndorsementNo: true },
    });

    const map = new Map(existing.map((x) => [x.policyEndorsementNo, x.id]));

    let created = 0;
    let updated = 0;

    // Create/update (safe without UNIQUE constraint)
    for (const p of clean) {
      const existingId = map.get(p.policyEndorsementNo);

      if (existingId) {
        await prisma.policy.update({
          where: { id: existingId },
          data: p,
        });
        updated++;
      } else {
        const createdRow = await prisma.policy.create({ data: p });
        map.set(p.policyEndorsementNo, createdRow.id);
        created++;
      }
    }

    return res.status(200).json({
      success: true,
      totalReceived: policies.length,
      valid: clean.length,
      created,
      updated,
      skipped: errors.length,
      errors, // row numbers + why skipped
    });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ success: false, message: "Server Error" });
  }
}