<?php
ini_set('display_errors',1);
error_reporting(E_ALL);

require_once $_SERVER['DOCUMENT_ROOT'] . '/core/includes/auth.php';
requireLogin();

require_once $_SERVER['DOCUMENT_ROOT'] . '/core/config/database.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/core/modules/billing/engine/calculate_block_bill.php';

if (!isset($_GET['id'])) {
    die("Missing invoice id");
}

$invoiceId = (int)$_GET['id'];

/* LOAD ORIGINAL */
$stmt = $pdo->prepare("
SELECT billing_account_id, period_start, period_end, unit_name
FROM invoices
WHERE id = ?
LIMIT 1
");
$stmt->execute([$invoiceId]);
$invoice = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$invoice) die("Invoice not found");

$accountId   = (int)$invoice['billing_account_id'];
$periodStart = $invoice['period_start'];
$periodEnd   = $invoice['period_end'];
$unitName    = $invoice['unit_name'];

$stmt = $pdo->prepare("
SELECT ba.*, s.company_id
FROM billing_accounts ba
JOIN structures s ON s.id = ba.structure_id
WHERE ba.id = ?
LIMIT 1
");
$stmt->execute([$accountId]);
$account = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$account) {
    die("Account not found");
}

$companyId = (int)$account['company_id'];

/* METERS */
$stmt = $pdo->prepare("
SELECT id, meter_number, tariff_id
FROM operational_meters
WHERE account_id = ?
AND unit_name = ?
AND status = 'ACTIVE'
");
$stmt->execute([$accountId, $unitName]);
$meters = $stmt->fetchAll(PDO::FETCH_ASSOC);

function insertLine(PDO $pdo, int $invoiceId, string $desc, float $qty, float $rate, float $total): void {
    $stmt = $pdo->prepare("
        INSERT INTO invoice_lines (invoice_id, description, quantity, unit_price, total)
        VALUES (?, ?, ?, ?, ?)
    ");
    $stmt->execute([$invoiceId, $desc, $qty, $rate, $total]);
}

function getSubtotal(PDO $pdo, int $invoiceId): float {
    $stmt = $pdo->prepare("
        SELECT COALESCE(SUM(total),0)
        FROM invoice_lines
        WHERE invoice_id = ?
    ");
    $stmt->execute([$invoiceId]);
    return (float)$stmt->fetchColumn();
}

function getConsumptionForPeriod(PDO $pdo, int $meterId, string $start, string $end): ?float
{
    $stmt = $pdo->prepare("
        SELECT reading_value
        FROM meter_readings
        WHERE meter_id = ?
        AND reading_date < ?
        ORDER BY reading_date DESC, id DESC
        LIMIT 1
    ");
    $stmt->execute([$meterId, $start]);
    $startReading = $stmt->fetchColumn();

    $stmt = $pdo->prepare("
        SELECT reading_value
        FROM meter_readings
        WHERE meter_id = ?
        AND reading_date <= ?
        ORDER BY reading_date DESC, id DESC
        LIMIT 1
    ");
    $stmt->execute([$meterId, $end]);
    $endReading = $stmt->fetchColumn();

    if ($startReading === false || $endReading === false) {
        return null;
    }

    $usage = (float)$endReading - (float)$startReading;

    if ($usage < 0) {
        return null;
    }

    return $usage;
}

/* BLOCK REGEN IF PAYMENTS EXIST */
$paymentCheck = $pdo->prepare("
SELECT COUNT(*)
FROM invoice_payments
WHERE invoice_id = ?
");
$paymentCheck->execute([$invoiceId]);

if ($paymentCheck->fetchColumn() > 0) {
    header("Location: /core/modules/billing/invoices/invoice_view.php?id=".$invoiceId."&error=has_payments");
    exit;
}

try {

    $pdo->beginTransaction();

    /* DELETE OLD INVOICE + LINES ONLY */
    $pdo->prepare("DELETE FROM invoice_lines WHERE invoice_id = ?")->execute([$invoiceId]);
    $pdo->prepare("DELETE FROM invoices WHERE id = ?")->execute([$invoiceId]);

    /* CREATE NEW */
    $stmt = $pdo->prepare("
    INSERT INTO invoices (
        company_id,
        billing_customer_id,
        billing_account_id,
        unit_name,
        invoice_number,
        invoice_date,
        due_date,
        period_start,
        period_end,
        subtotal,
        vat_rate,
        vat_amount,
        total,
        status,
        created_by
    )
    VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
    ");

    $stmt->execute([
        $companyId,
        $account['customer_id'],
        $accountId,
        $unitName,
        'INV-'.date('Ym').'-'.time(),
        date('Y-m-d'),
        date('Y-m-d', strtotime('+14 days')),
        $periodStart,
        $periodEnd,
        0,
        0.15,
        0,
        0,
        'ISSUED',
        $_SESSION['user_id']
    ]);

    $newInvoiceId = (int)$pdo->lastInsertId();
    $hasLines = false;

    /* METERS */
    foreach($meters as $m){

        $meterId     = (int)$m['id'];
        $meterNumber = $m['meter_number'];
        $tariffId    = (int)$m['tariff_id'];

        if (!$tariffId) {
            continue;
        }

        $usage = getConsumptionForPeriod($pdo, $meterId, $periodStart, $periodEnd);

        if ($usage === null) {
            continue;
        }

        insertLine($pdo, $newInvoiceId, "METER_HEADER::".$meterNumber, 0, 0, 0);

        $result = calculateBlockBill($pdo, $tariffId, $usage);

        $meterSubtotal = 0;

        foreach($result['breakdown'] as $row){
            insertLine(
                $pdo,
                $newInvoiceId,
                $row['label'],
                (float)$row['units'],
                (float)$row['rate'],
                (float)$row['amount']
            );
            $meterSubtotal += (float)$row['amount'];
            $hasLines = true;
        }

        /* METER CHARGES */
        $charges = $pdo->prepare("
        SELECT bc.*
        FROM meter_charges mc
        JOIN billing_charges bc ON bc.id = mc.charge_id
        WHERE mc.meter_id = ?
        AND bc.applies_to = 'METER'
        AND bc.active = 1
        ");
        $charges->execute([$meterId]);

        foreach($charges as $c){

            $amount = $c['charge_type'] == 'percentage'
                ? ($usage * ((float)$c['charge_value'] / 100))
                : (float)$c['charge_value'];

            insertLine(
                $pdo,
                $newInvoiceId,
                "METER_CHARGE::".$meterNumber."::".$c['charge_name'],
                1,
                $amount,
                $amount
            );

            $hasLines = true;
        }
    }

    /* UNIT CHARGES */
    $charges = $pdo->prepare("
    SELECT bc.*
    FROM unit_charges uc
    JOIN billing_charges bc ON bc.id = uc.charge_id
    WHERE uc.account_id = ?
    AND uc.unit_name = ?
    AND bc.applies_to = 'UNIT'
    AND bc.active = 1
    ");
    $charges->execute([$accountId, $unitName]);

    foreach($charges as $c){

        $subtotal = getSubtotal($pdo, $newInvoiceId);

        $amount = $c['charge_type'] == 'percentage'
            ? ($subtotal * ((float)$c['charge_value'] / 100))
            : (float)$c['charge_value'];

        insertLine(
            $pdo,
            $newInvoiceId,
            "UNIT_CHARGE::".$c['charge_name'],
            1,
            $amount,
            $amount
        );

        $hasLines = true;
    }

    /* ACCOUNT CHARGES */
    $charges = $pdo->prepare("
    SELECT bc.*
    FROM account_charges ac
    JOIN billing_charges bc ON bc.id = ac.charge_id
    WHERE ac.account_id = ?
    AND bc.applies_to = 'ACCOUNT'
    AND bc.active = 1
    ");
    $charges->execute([$accountId]);

    foreach($charges as $c){

        $subtotal = getSubtotal($pdo, $newInvoiceId);

        $amount = $c['charge_type'] == 'percentage'
            ? ($subtotal * ((float)$c['charge_value'] / 100))
            : (float)$c['charge_value'];

        insertLine(
            $pdo,
            $newInvoiceId,
            "ACCOUNT_CHARGE::".$c['charge_name'],
            1,
            $amount,
            $amount
        );

        $hasLines = true;
    }

    if (!$hasLines) {
        $pdo->prepare("DELETE FROM invoice_lines WHERE invoice_id = ?")->execute([$newInvoiceId]);
        $pdo->prepare("DELETE FROM invoices WHERE id = ?")->execute([$newInvoiceId]);
        $pdo->commit();
        header("Location: /core/modules/billing/invoices/invoice_view.php?id=".$invoiceId."&error=no_lines");
        exit;
    }

    /* FINAL TOTAL */
    $subtotal = getSubtotal($pdo, $newInvoiceId);
    $vat = $subtotal * 0.15;
    $total = $subtotal + $vat;

    $pdo->prepare("
    UPDATE invoices
    SET subtotal = ?, vat_amount = ?, total = ?
    WHERE id = ?
    ")->execute([$subtotal, $vat, $total, $newInvoiceId]);

    $pdo->commit();

    header("Location: /core/modules/billing/invoices/invoice_view.php?id=".$newInvoiceId."&regen=success");
    exit;

} catch(Exception $e) {

    if ($pdo->inTransaction()) {
        $pdo->rollBack();
    }

    die("Rebuild failed: " . $e->getMessage());
}