<?php

declare(strict_types=1);

/**
 * RBE Utilities Energy Engine helpers
 *
 * All functions expect a PDO connection to the RBE database.
 */

function get_flecto_register_deltas(PDO $db, string $serial, string $start, string $end): array
{
    $sqlFirst = "SELECT * FROM flecto_meter_readings WHERE serial = ? AND created_at >= ? ORDER BY created_at ASC LIMIT 1";
    $sqlLast  = "SELECT * FROM flecto_meter_readings WHERE serial = ? AND created_at <= ? ORDER BY created_at DESC LIMIT 1";

    $st = $db->prepare($sqlFirst);
    $st->execute([$serial, $start]);
    $first = $st->fetch(PDO::FETCH_ASSOC) ?: null;

    $st = $db->prepare($sqlLast);
    $st->execute([$serial, $end]);
    $last = $st->fetch(PDO::FETCH_ASSOC) ?: null;

    $regs = [];
    foreach (range('a', 'o') as $letter) {
        $key = 'reg_' . $letter;
        $startVal = $first && isset($first[$key]) ? (float)$first[$key] : 0.0;
        $endVal   = $last && isset($last[$key]) ? (float)$last[$key] : 0.0;
        $regs[$key] = max($endVal - $startVal, 0.0);
    }

    return $regs;
}

function calculate_meter_import_export(array $deltas, bool $touEnabled): array
{
    $get = static function (array $src, string $key): float {
        return isset($src[$key]) ? (float)$src[$key] : 0.0;
    };

    $import_t1 = $get($deltas, 'reg_a');
    $import_t2 = $get($deltas, 'reg_e');
    $import_t3 = $get($deltas, 'reg_f');
    $import_t5 = $get($deltas, 'reg_h');
    $import_t6 = $get($deltas, 'reg_l');

    $export_t1 = $get($deltas, 'reg_b');
    $export_t5 = $get($deltas, 'reg_i');
    $export_t6 = $get($deltas, 'reg_m');

    $solar_export = $export_t1 + $export_t5 + $export_t6;
    $total_import = $import_t1 + $import_t2 + $import_t3 + $import_t5 + $import_t6;
    $total_export = $solar_export;

    if ($touEnabled) {
        $billing_import = $import_t5 + $import_t6;
        $billing_export = $export_t5 + $export_t6;
    } else {
        $billing_import = $import_t1;
        $billing_export = $export_t1;
    }

    return [
        'import_t1'      => $import_t1,
        'import_t2'      => $import_t2,
        'import_t3'      => $import_t3,
        'import_t5'      => $import_t5,
        'import_t6'      => $import_t6,
        'export_t1'      => $export_t1,
        'export_t5'      => $export_t5,
        'export_t6'      => $export_t6,
        'solar_export'   => $solar_export,
        'total_import'   => $total_import,
        'total_export'   => $total_export,
        'billing_import' => $billing_import,
        'billing_export' => $billing_export,
    ];
}

function get_bulk_meter_totals(
    PDO $db,
    int $bulkMeterId,
    string $start,
    string $end,
    bool $touEnabled = false,
    ?float $bulkMeterReadingImportKwh = null
): array {
    $st = $db->prepare("SELECT serial_number FROM flecto_meters WHERE bulk_meter_id = ?");
    $st->execute([$bulkMeterId]);
    $rows = $st->fetchAll(PDO::FETCH_ASSOC);

    $bulkImport = 0.0;
    $bulkExport = 0.0;

    foreach ($rows as $m) {
        $serial = (string)$m['serial_number'];
        $deltas = get_flecto_register_deltas($db, $serial, $start, $end);
        $calc   = calculate_meter_import_export($deltas, $touEnabled);
        $bulkImport += $calc['billing_import'];
        $bulkExport += $calc['billing_export'];
    }

    $bulkLossKwh = null;
    $bulkLossPct = null;

    if ($bulkMeterReadingImportKwh !== null) {
        $bulkLossKwh = $bulkMeterReadingImportKwh - $bulkImport;
        if ($bulkMeterReadingImportKwh > 0.0) {
            $bulkLossPct = ($bulkLossKwh / $bulkMeterReadingImportKwh) * 100.0;
        } else {
            $bulkLossPct = 0.0;
        }
    }

    return [
        'bulk_import'     => $bulkImport,
        'bulk_export'     => $bulkExport,
        'bulk_loss_kwh'   => $bulkLossKwh,
        'bulk_loss_pct'   => $bulkLossPct,
    ];
}

function get_site_totals(
    PDO $db,
    int $municipalMeterId,
    string $start,
    string $end,
    bool $touEnabled = false
): array {
    $st = $db->prepare("SELECT id FROM bulk_meters WHERE municipal_meter_id = ?");
    $st->execute([$municipalMeterId]);
    $bulkRows = $st->fetchAll(PDO::FETCH_ASSOC);

    $siteImport = 0.0;
    $siteExport = 0.0;

    foreach ($bulkRows as $b) {
        $totals = get_bulk_meter_totals($db, (int)$b['id'], $start, $end, $touEnabled, null);
        $siteImport += (float)$totals['bulk_import'];
        $siteExport += (float)$totals['bulk_export'];
    }

    $siteNetImport = 0.0;
    $siteNetExport = 0.0;

    if ($siteExport > $siteImport) {
        $siteNetExport = $siteExport - $siteImport;
    } else {
        $siteNetImport = $siteImport - $siteExport;
    }

    return [
        'site_total_import' => $siteImport,
        'site_total_export' => $siteExport,
        'site_net_import'   => $siteNetImport,
        'site_net_export'   => $siteNetExport,
    ];
}

function compare_levels(
    PDO $db,
    int $municipalMeterId,
    string $start,
    string $end,
    bool $touEnabled = false,
    ?float $municipalMeterImportKwh = null
): array {
    $site = get_site_totals($db, $municipalMeterId, $start, $end, $touEnabled);

    $municipalLossKwh = null;
    $municipalLossPct = null;

    if ($municipalMeterImportKwh !== null) {
        $municipalLossKwh = $municipalMeterImportKwh - $site['site_total_import'];
        if ($municipalMeterImportKwh > 0.0) {
            $municipalLossPct = ($municipalLossKwh / $municipalMeterImportKwh) * 100.0;
        } else {
            $municipalLossPct = 0.0;
        }
    }

    return [
        'site'                => $site,
        'municipal_loss_kwh'  => $municipalLossKwh,
        'municipal_loss_pct'  => $municipalLossPct,
    ];
}

function get_energy_breakdown(
    PDO $db,
    ?int $tenantId,
    ?int $propertyId,
    ?int $bulkMeterId,
    ?int $siteGroupId,
    string $start,
    string $end,
    bool $touEnabled = false
): array {
    $perTenant = [];

    if ($tenantId !== null) {
        $st = $db->prepare("SELECT serial_number FROM flecto_meters WHERE tenant_id = ?");
        $st->execute([$tenantId]);
        $meters = $st->fetchAll(PDO::FETCH_ASSOC);

        $tenantTotals = [
            'import_t1'      => 0.0,
            'import_t2'      => 0.0,
            'import_t3'      => 0.0,
            'import_t5'      => 0.0,
            'import_t6'      => 0.0,
            'export_t1'      => 0.0,
            'export_t5'      => 0.0,
            'export_t6'      => 0.0,
            'solar_export'   => 0.0,
            'billing_import' => 0.0,
            'billing_export' => 0.0,
            'total_import'   => 0.0,
            'total_export'   => 0.0,
        ];

        foreach ($meters as $m) {
            $serial = (string)$m['serial_number'];
            $deltas = get_flecto_register_deltas($db, $serial, $start, $end);
            $calc   = calculate_meter_import_export($deltas, $touEnabled);
            foreach ($tenantTotals as $k => $v) {
                $tenantTotals[$k] = $v + (isset($calc[$k]) ? (float)$calc[$k] : 0.0);
            }
        }

        $perTenant = $tenantTotals;
    }

    $perBulk = null;
    if ($bulkMeterId !== null) {
        $perBulk = get_bulk_meter_totals($db, $bulkMeterId, $start, $end, $touEnabled, null);
    }

    $perSite = null;
    if ($siteGroupId !== null) {
        $perSite = get_site_totals($db, $siteGroupId, $start, $end, $touEnabled);
    }

    return [
        'tenant' => $perTenant,
        'bulk'   => $perBulk,
        'site'   => $perSite,
    ];
}

