import { getPool } from "../database/db";
import { logger } from "../utils/logger";

interface QuoteFilter {
  search?: string;
  status?: string;
  startDate?: string;
  endDate?: string;
}

interface QuoteBody {
  quote_no?: string;
  quote_date: string;
  valid_until?: string;
  customer_objid?: number;
  customer_name?: string;
  status?: string;
  manager?: string;
  domestic_type?: string;
  payment_terms?: string;
  delivery_method?: string;
  notes?: string;
  customer_ceo?: string;
  customer_biz_no?: string;
  customer_address?: string;
  customer_contact?: string;
  customer_phone?: string;
  incoterms?: string;
  currency?: string;
  exchange_rate?: number;
  port_of_loading?: string;
  port_of_discharge?: string;
  shipment_date?: string;
  hs_code?: string;
  country_of_origin?: string;
  lc_number?: string;
  trade_notes?: string;
  items?: QuoteItem[];
}

interface QuoteItem {
  item_no?: number;
  item_code?: string;
  item_name?: string;
  spec?: string;
  qty?: number;
  unit?: string;
  request_length?: number;
  unit_price?: number;
  supply_amount?: number;
  vat_amount?: number;
  total_amount?: number;
  notes?: string;
}

export async function getList(companyCode: string, filter: QuoteFilter) {
  const pool = getPool();
  const conditions: string[] = [];
  const params: any[] = [];
  let idx = 1;

  if (companyCode !== "*") {
    conditions.push(`q.company_code = $${idx}`);
    params.push(companyCode);
    idx++;
  }

  conditions.push(`q.use_yn = 'Y'`);

  if (filter.search) {
    conditions.push(`(q.quote_no ILIKE $${idx} OR q.customer_name ILIKE $${idx})`);
    params.push(`%${filter.search}%`);
    idx++;
  }

  if (filter.status) {
    conditions.push(`q.status = $${idx}`);
    params.push(filter.status);
    idx++;
  }

  if (filter.startDate) {
    conditions.push(`q.quote_date >= $${idx}`);
    params.push(filter.startDate);
    idx++;
  }

  if (filter.endDate) {
    conditions.push(`q.quote_date <= $${idx}`);
    params.push(filter.endDate);
    idx++;
  }

  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";

  const query = `
    SELECT q.objid, q.quote_no, q.quote_date, q.valid_until,
           q.customer_objid, q.customer_name, q.status, q.manager,
           q.domestic_type, q.payment_terms, q.delivery_method, q.notes,
           q.total_supply, q.total_vat, q.total_amount,
           q.customer_ceo, q.customer_biz_no, q.customer_address,
           q.customer_contact, q.customer_phone,
           q.incoterms, q.currency, q.exchange_rate,
           q.port_of_loading, q.port_of_discharge, q.shipment_date,
           q.hs_code, q.country_of_origin, q.lc_number, q.trade_notes,
           q.revision_count, q.created_by, q.created_at, q.updated_at
    FROM quote_mng q
    ${where}
    ORDER BY q.created_at DESC
  `;

  const result = await pool.query(query, params);
  logger.info("견적 목록 조회", { companyCode, count: result.rowCount });
  return result.rows;
}

export async function getById(companyCode: string, objid: number) {
  const pool = getPool();

  // 마스터
  const masterRes = await pool.query(
    `SELECT * FROM quote_mng WHERE objid = $1 AND company_code = $2 AND use_yn = 'Y'`,
    [objid, companyCode],
  );

  if (masterRes.rowCount === 0) return null;

  // 품목
  const detailRes = await pool.query(
    `SELECT * FROM quote_detail WHERE quote_objid = $1 ORDER BY item_no`,
    [objid],
  );

  return { ...masterRes.rows[0], items: detailRes.rows };
}

export async function generateNumber(companyCode: string): Promise<string> {
  const pool = getPool();
  const year = new Date().getFullYear();
  const prefix = `QT-${year}-`;

  const res = await pool.query(
    `SELECT quote_no FROM quote_mng
     WHERE company_code = $1 AND quote_no LIKE $2
     ORDER BY quote_no DESC LIMIT 1`,
    [companyCode, `${prefix}%`],
  );

  let seq = 1;
  if (res.rowCount && res.rowCount > 0) {
    const last = res.rows[0].quote_no as string;
    const lastSeq = parseInt(last.replace(prefix, ""), 10);
    if (!isNaN(lastSeq)) seq = lastSeq + 1;
  }

  return `${prefix}${String(seq).padStart(4, "0")}`;
}

export async function create(companyCode: string, userId: string, body: QuoteBody) {
  const pool = getPool();
  const client = await pool.connect();

  try {
    await client.query("BEGIN");

    const quoteNo = body.quote_no || (await generateNumber(companyCode));

    // 합계 계산
    const items = body.items ?? [];
    const totalSupply = items.reduce((s, i) => s + (i.supply_amount ?? 0), 0);
    const totalVat = items.reduce((s, i) => s + (i.vat_amount ?? 0), 0);
    const totalAmount = totalSupply + totalVat;

    const masterRes = await client.query(
      `INSERT INTO quote_mng (
        quote_no, quote_date, valid_until, customer_objid, customer_name,
        status, manager, domestic_type, payment_terms, delivery_method, notes,
        total_supply, total_vat, total_amount,
        customer_ceo, customer_biz_no, customer_address, customer_contact, customer_phone,
        incoterms, currency, exchange_rate, port_of_loading, port_of_discharge,
        shipment_date, hs_code, country_of_origin, lc_number, trade_notes,
        company_code, created_by, updated_by
      ) VALUES (
        $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,
        $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$31
      ) RETURNING objid`,
      [
        quoteNo, body.quote_date, body.valid_until || null,
        body.customer_objid || null, body.customer_name || null,
        body.status || "draft", body.manager || null,
        body.domestic_type || "국내", body.payment_terms || null,
        body.delivery_method || null, body.notes || null,
        totalSupply, totalVat, totalAmount,
        body.customer_ceo || null, body.customer_biz_no || null,
        body.customer_address || null, body.customer_contact || null,
        body.customer_phone || null,
        body.incoterms || null, body.currency || "KRW",
        body.exchange_rate || null, body.port_of_loading || null,
        body.port_of_discharge || null, body.shipment_date || null,
        body.hs_code || null, body.country_of_origin || null,
        body.lc_number || null, body.trade_notes || null,
        companyCode, userId,
      ],
    );

    const quoteObjid = masterRes.rows[0].objid;

    // 품목 INSERT
    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      await client.query(
        `INSERT INTO quote_detail (
          quote_objid, item_no, item_code, item_name, spec,
          qty, unit, request_length, unit_price,
          supply_amount, vat_amount, total_amount, notes, company_code
        ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)`,
        [
          quoteObjid, i + 1, item.item_code || null, item.item_name || null,
          item.spec || null, item.qty ?? 0, item.unit || "EA",
          item.request_length || null, item.unit_price ?? 0,
          item.supply_amount ?? 0, item.vat_amount ?? 0,
          item.total_amount ?? 0, item.notes || null, companyCode,
        ],
      );
    }

    await client.query("COMMIT");
    logger.info("견적 등록 완료", { companyCode, quoteNo, quoteObjid });
    return { objid: quoteObjid, quote_no: quoteNo };
  } catch (error) {
    await client.query("ROLLBACK");
    throw error;
  } finally {
    client.release();
  }
}

export async function update(companyCode: string, userId: string, objid: number, body: QuoteBody) {
  const pool = getPool();
  const client = await pool.connect();

  try {
    await client.query("BEGIN");

    const items = body.items ?? [];
    const totalSupply = items.reduce((s, i) => s + (i.supply_amount ?? 0), 0);
    const totalVat = items.reduce((s, i) => s + (i.vat_amount ?? 0), 0);
    const totalAmount = totalSupply + totalVat;

    await client.query(
      `UPDATE quote_mng SET
        quote_date=$1, valid_until=$2, customer_objid=$3, customer_name=$4,
        status=$5, manager=$6, domestic_type=$7, payment_terms=$8,
        delivery_method=$9, notes=$10,
        total_supply=$11, total_vat=$12, total_amount=$13,
        customer_ceo=$14, customer_biz_no=$15, customer_address=$16,
        customer_contact=$17, customer_phone=$18,
        incoterms=$19, currency=$20, exchange_rate=$21,
        port_of_loading=$22, port_of_discharge=$23, shipment_date=$24,
        hs_code=$25, country_of_origin=$26, lc_number=$27, trade_notes=$28,
        revision_count = revision_count + 1,
        updated_by=$29, updated_at=CURRENT_TIMESTAMP
      WHERE objid=$30 AND company_code=$31`,
      [
        body.quote_date, body.valid_until || null,
        body.customer_objid || null, body.customer_name || null,
        body.status || "draft", body.manager || null,
        body.domestic_type || "국내", body.payment_terms || null,
        body.delivery_method || null, body.notes || null,
        totalSupply, totalVat, totalAmount,
        body.customer_ceo || null, body.customer_biz_no || null,
        body.customer_address || null, body.customer_contact || null,
        body.customer_phone || null,
        body.incoterms || null, body.currency || "KRW",
        body.exchange_rate || null, body.port_of_loading || null,
        body.port_of_discharge || null, body.shipment_date || null,
        body.hs_code || null, body.country_of_origin || null,
        body.lc_number || null, body.trade_notes || null,
        userId, objid, companyCode,
      ],
    );

    // 기존 품목 삭제 후 재등록
    await client.query(`DELETE FROM quote_detail WHERE quote_objid = $1`, [objid]);

    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      await client.query(
        `INSERT INTO quote_detail (
          quote_objid, item_no, item_code, item_name, spec,
          qty, unit, request_length, unit_price,
          supply_amount, vat_amount, total_amount, notes, company_code
        ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)`,
        [
          objid, i + 1, item.item_code || null, item.item_name || null,
          item.spec || null, item.qty ?? 0, item.unit || "EA",
          item.request_length || null, item.unit_price ?? 0,
          item.supply_amount ?? 0, item.vat_amount ?? 0,
          item.total_amount ?? 0, item.notes || null, companyCode,
        ],
      );
    }

    await client.query("COMMIT");
    logger.info("견적 수정 완료", { companyCode, objid });
  } catch (error) {
    await client.query("ROLLBACK");
    throw error;
  } finally {
    client.release();
  }
}

export async function remove(companyCode: string, objid: number) {
  const pool = getPool();
  await pool.query(
    `UPDATE quote_mng SET use_yn = 'N', updated_at = CURRENT_TIMESTAMP WHERE objid = $1 AND company_code = $2`,
    [objid, companyCode],
  );
  logger.info("견적 삭제(소프트)", { companyCode, objid });
}
