import { randomBytes } from 'crypto';
import nodemailer from 'nodemailer';
import { getPool } from '../db.js';
import type { RowDataPacket } from 'mysql2';

export interface InvoiceLineItem {
  description: string;
  quantity: number;
  unit_price: number;
  amount: number;
}

export interface Invoice extends RowDataPacket {
  id: number;
  customer_id: string;
  invoice_number: string;
  amount: number;
  currency: string;
  status: 'draft' | 'sent' | 'paid' | 'overdue';
  period_start: string;
  period_end: string;
  line_items: InvoiceLineItem[];
  sent_at: string | null;
  paid_at: string | null;
  created_at: string;
}

function generateInvoiceNumber(): string {
  const date = new Date().toISOString().slice(0, 10).replace(/-/g, '');
  const suffix = randomBytes(4).toString('hex');
  return `SMCP-${date}-${suffix}`;
}

function normalizeInvoice(invoice: Invoice): Invoice {
  if (typeof invoice.line_items === 'string') {
    invoice.line_items = JSON.parse(invoice.line_items);
  }
  return invoice;
}

export async function createInvoice(
  customerId: string,
  amount: number,
  lineItems: InvoiceLineItem[],
  periodStart: string,
  periodEnd: string
): Promise<Invoice> {
  const invoiceNumber = generateInvoiceNumber();
  try {
    await getPool().query(
      `INSERT INTO invoices (customer_id, invoice_number, amount, line_items, period_start, period_end)
       VALUES (?, ?, ?, ?, ?, ?)`,
      [customerId, invoiceNumber, amount, JSON.stringify(lineItems), periodStart, periodEnd]
    );
  } catch (err: any) {
    if (err.errno === 1062 && err.message.includes('uq_customer_period')) {
      const [rows] = await getPool().query<Invoice[]>(
        'SELECT * FROM invoices WHERE customer_id = ? AND period_start = ?',
        [customerId, periodStart]
      );
      return normalizeInvoice(rows[0]);
    }
    throw err;
  }
  const [rows] = await getPool().query<Invoice[]>(
    'SELECT * FROM invoices WHERE invoice_number = ?',
    [invoiceNumber]
  );
  return normalizeInvoice(rows[0]);
}

export async function getCustomerInvoices(customerId: string): Promise<Invoice[]> {
  const [rows] = await getPool().query<Invoice[]>(
    'SELECT * FROM invoices WHERE customer_id = ? ORDER BY created_at DESC',
    [customerId]
  );
  return rows.map(normalizeInvoice);
}

export async function getInvoiceByNumber(invoiceNumber: string): Promise<Invoice | null> {
  const [rows] = await getPool().query<Invoice[]>(
    'SELECT * FROM invoices WHERE invoice_number = ?',
    [invoiceNumber]
  );
  return rows[0] ? normalizeInvoice(rows[0]) : null;
}

export async function markInvoiceSent(invoiceNumber: string): Promise<void> {
  await getPool().query(
    "UPDATE invoices SET status = 'sent', sent_at = NOW() WHERE invoice_number = ?",
    [invoiceNumber]
  );
}

export async function markInvoicePaid(invoiceNumber: string): Promise<void> {
  await getPool().query(
    "UPDATE invoices SET status = 'paid', paid_at = NOW() WHERE invoice_number = ?",
    [invoiceNumber]
  );
}

export async function emailInvoice(invoice: Invoice, toEmail: string): Promise<void> {
  const transport = nodemailer.createTransport({
    host: process.env.FETCHERPAY_SMTP_HOST ?? 'mail.fetcherpay.com',
    port: parseInt(process.env.FETCHERPAY_SMTP_PORT ?? '30587', 10),
    secure: false,
    auth: {
      user: process.env.BILLING_EMAIL ?? process.env.FETCHERPAY_EMAIL,
      pass: process.env.BILLING_PASSWORD ?? process.env.FETCHERPAY_PASSWORD,
    },
    tls: { rejectUnauthorized: false },
  });
  await transport.sendMail({
    from: process.env.BILLING_FROM ?? 'billing@squaremcp.com',
    to: toEmail,
    subject: `Invoice ${invoice.invoice_number} from SquareMCP`,
    html: `
      <h1>Invoice ${invoice.invoice_number}</h1>
      <p>Billing period: ${invoice.period_start} – ${invoice.period_end}</p>
      <p>Amount due: $${invoice.amount} ${invoice.currency}</p>
      <table>
        <tr><th>Description</th><th>Qty</th><th>Unit price</th><th>Amount</th></tr>
        ${invoice.line_items.map((li) =>
          `<tr><td>${li.description}</td><td>${li.quantity}</td><td>$${li.unit_price}</td><td>$${li.amount}</td></tr>`
        ).join('')}
      </table>
    `,
  });
}

export async function generateMonthlyInvoice(customerId: string): Promise<Invoice | null> {
  const now = new Date();
  const prevMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1);
  const prevMonthEnd = new Date(now.getFullYear(), now.getMonth(), 0);

  const [usageRows] = await getPool().query<any[]>(
    `SELECT platform, COUNT(*) as count FROM usage_logs
     WHERE customer_id = ?
       AND created_at >= DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 MONTH), '%Y-%m-01')
       AND created_at < DATE_FORMAT(NOW(), '%Y-%m-01')
     GROUP BY platform`,
    [customerId]
  );

  if (!usageRows.length) return null;

  const lineItems: InvoiceLineItem[] = [];
  let total = 0;

  for (const row of usageRows) {
    const qty = row.count;
    const unitPrice = 0.05;
    const amount = qty * unitPrice;
    total += amount;
    lineItems.push({
      description: `${row.platform} actions`,
      quantity: qty,
      unit_price: unitPrice,
      amount: parseFloat(amount.toFixed(2)),
    });
  }

  return createInvoice(
    customerId,
    parseFloat(total.toFixed(2)),
    lineItems,
    prevMonthStart.toISOString().slice(0, 10),
    prevMonthEnd.toISOString().slice(0, 10)
  );
}
