<?php
namespace App\Controllers;

use App\Core\Acl;
use App\Core\Audit;
use App\Core\Auth;
use App\Core\Controller;
use App\Core\Database;
use App\Core\Dates;
use App\Core\Flash;
use App\Core\Num;
use App\Core\Request;
use App\Core\Settings;
use App\Services\AcpService;
use App\Services\DashboardService;
use App\Services\ExportService;

/** Modul Average Collection Period (ACP) & kinerja penagihan. */
class AcpController extends Controller
{
    protected string $module = 'acp';

    private function ctx(): array
    {
        $preset = (string)Request::get('preset', '');
        $today = Dates::today();
        if ($preset !== '' && $preset !== 'custom') {
            [$from, $to] = Dates::range($preset, $today);
            if ($to > $today) $to = $today;
        } else {
            $from = Request::date('dari') ?: Dates::monthStart($today);
            $to   = Request::date('sampai') ?: $today;
        }
        $method = in_array(Request::get('metode', ''), ['finansial', 'operasional'], true)
                ? (string)Request::get('metode') : Settings::str('acp.metode_default', 'operasional');
        $filters = PiutangController::readFilters(false);
        [$s, $sp] = Acl::invoiceScopeSql('i');
        $filters['_scope_sql'] = $s;
        $filters['_scope_params'] = $sp;
        return [$from, $to, $method, $filters, $preset];
    }

    public function index(): void
    {
        [$from, $to, $method, $filters, $preset] = $this->ctx();
        $dim = (string)Request::get('dimensi', 'customer');
        if (!in_array($dim, ['customer', 'salesperson', 'area', 'business_unit', 'job_category', 'outlet', 'collection_officer', 'revenue_category'], true)) {
            $dim = 'customer';
        }

        $hasil = AcpService::calculate($from, $to, $filters, $method);
        $lain  = AcpService::calculate($from, $to, $filters, $method === 'finansial' ? 'operasional' : 'finansial');
        $year = (int)substr($to, 0, 4);
        $target = AcpService::target($year, (int)substr($to, 5, 2));

        $this->view('acp/index', [
            'judul' => 'Average Collection Period (ACP)',
            'subjudul' => Dates::periodLabel($from, $to),
            'from' => $from, 'to' => $to, 'method' => $method, 'preset' => $preset,
            'hasil' => $hasil, 'pembanding' => $lain,
            'target' => $target,
            'indikator' => acpIndicator($hasil['acp_hari'], $target ? (float)$target['target_days'] : null,
                                        $target ? (float)$target['tolerance_days'] : 5.0),
            'trend' => AcpService::monthlyTrend($year, $filters, $method),
            'comparisons' => AcpService::comparisons($to, $filters, $method),
            'byDim' => AcpService::byDimension($dim, $from, $to, $filters, 50),
            'dimensi' => $dim,
            'dimensiOptions' => [
                'customer' => 'Customer', 'salesperson' => 'Sales', 'area' => 'Area',
                'business_unit' => 'Unit Bisnis', 'job_category' => 'Kategori Pekerjaan',
                'outlet' => 'Outlet', 'collection_officer' => 'Petugas Penagihan',
                'revenue_category' => 'PMSC / By Case',
            ],
            'filters' => PiutangController::readFilters(false),
            'opsi' => DashboardService::filterOptions(),
            'metodeOptions' => AcpService::METODE,
        ]);
    }

    public function export(): void
    {
        [$from, $to, $method, $filters] = $this->ctx();
        $dim = (string)Request::get('dimensi', 'customer');
        $hasil = AcpService::calculate($from, $to, $filters, $method);
        $rows = AcpService::byDimension($dim, $from, $to, $filters, 5000);
        $dimLabel = ['customer' => 'Customer', 'salesperson' => 'Sales', 'area' => 'Area',
                     'business_unit' => 'Unit Bisnis', 'job_category' => 'Kategori Pekerjaan',
                     'outlet' => 'Outlet', 'collection_officer' => 'Petugas Penagihan',
                     'revenue_category' => 'PMSC / By Case'][$dim] ?? 'Kelompok';

        $data = array_map(fn($r) => [
            'grup' => $r['grup_label'], 'jumlah' => $r['jumlah_invoice'], 'nilai' => $r['nilai_tertagih'],
            'rata' => $r['rata_hari'], 'tertimbang' => $r['rata_tertimbang'],
            'min' => $r['min_hari'], 'maks' => $r['maks_hari'],
            'tepat' => $r['persen_tepat_waktu'], 'telat' => $r['rata_telat'],
            'target' => $r['target'], 'status' => $r['indikator']['label'],
        ], $rows);

        $kpi = [
            ['label' => 'ACP', 'value' => $hasil['acp_hari'] === null ? '-' : Num::fmt($hasil['acp_hari'], 1) . ' hari'],
            ['label' => 'Jumlah Invoice', 'value' => Num::fmt($hasil['jumlah_invoice'] ?? 0, 0)],
            ['label' => 'Nilai', 'value' => Num::rupiah($hasil['nilai_tertagih'] ?? ($hasil['penerimaan_kas'] ?? 0))],
            ['label' => '% Tepat Waktu', 'value' => isset($hasil['persen_tepat_waktu']) && $hasil['persen_tepat_waktu'] !== null ? Num::percent($hasil['persen_tepat_waktu']) : '-'],
        ];

        ExportService::send((string)Request::get('format', 'xlsx'), [
            'judul' => 'LAPORAN AVERAGE COLLECTION PERIOD (ACP)',
            'subjudul' => 'Dikelompokkan per ' . $dimLabel,
            'periode' => Dates::periodLabel($from, $to),
            'metode' => $hasil['metode_label'],
            'filter' => PiutangController::filterLabels(PiutangController::readFilters(false)),
            'nama_berkas' => 'laporan_acp', 'sheet' => 'ACP', 'orientasi' => 'landscape',
            'kpi' => $kpi,
        ], [
            ['label' => $dimLabel,             'key' => 'grup',       'type' => 'text', 'width' => 34, 'pdf_width' => 2.4],
            ['label' => 'Invoice Lunas',       'key' => 'jumlah',     'type' => 'int'],
            ['label' => 'Nilai Tertagih',      'key' => 'nilai',      'type' => 'money'],
            ['label' => 'Rata Hari',           'key' => 'rata',       'type' => 'dec'],
            ['label' => 'Rata Tertimbang',     'key' => 'tertimbang', 'type' => 'dec'],
            ['label' => 'Min',                 'key' => 'min',        'type' => 'int'],
            ['label' => 'Maks',                'key' => 'maks',       'type' => 'int'],
            ['label' => '% Tepat Waktu',       'key' => 'tepat',      'type' => 'dec'],
            ['label' => 'Rata Keterlambatan',  'key' => 'telat',      'type' => 'dec'],
            ['label' => 'Target (hari)',       'key' => 'target',     'type' => 'dec'],
            ['label' => 'Status',              'key' => 'status',     'type' => 'text'],
        ], $data);
    }

    public function targets(): void
    {
        $year = Request::int('tahun', (int)date('Y'));
        $db = Database::i();
        $this->view('acp/target', [
            'judul' => 'Target ACP',
            'subjudul' => 'Penetapan target Average Collection Period per lingkup',
            'tahun' => $year,
            'targets' => $db->all(
                "SELECT t.*, CASE t.scope
                        WHEN 'area' THEN (SELECT name FROM areas WHERE id=t.scope_id)
                        WHEN 'business_unit' THEN (SELECT name FROM business_units WHERE id=t.scope_id)
                        WHEN 'customer' THEN (SELECT name FROM customers WHERE id=t.scope_id)
                        WHEN 'salesperson' THEN (SELECT name FROM salespersons WHERE id=t.scope_id)
                        WHEN 'job_category' THEN (SELECT name FROM job_categories WHERE id=t.scope_id)
                        ELSE 'Seluruh Perusahaan' END AS scope_label
                   FROM acp_targets t
                  WHERE t.deleted_at IS NULL AND t.period_year = :y
                  ORDER BY t.scope, t.period_month, scope_label", ['y' => $year]),
            'areas' => $db->all('SELECT id,name FROM areas WHERE deleted_at IS NULL ORDER BY name'),
            'bus' => $db->all('SELECT id,name FROM business_units WHERE deleted_at IS NULL ORDER BY name'),
            'salespersons' => $db->all('SELECT id,name FROM salespersons WHERE deleted_at IS NULL AND is_active=1 ORDER BY name'),
            'jobCats' => $db->all('SELECT id,name FROM job_categories WHERE deleted_at IS NULL ORDER BY name'),
        ]);
    }

    public function saveTarget(): void
    {
        $scope = (string)Request::post('scope', 'global');
        if (!in_array($scope, ['global', 'area', 'business_unit', 'customer', 'salesperson', 'job_category'], true)) {
            Flash::error('Lingkup target tidak valid.');
            $this->back('/acp/target');
        }
        $scopeId = $scope === 'global' ? null : (Request::int('scope_id') ?: null);
        $year = Request::int('period_year', (int)date('Y'));
        $month = Request::int('period_month', 0) ?: null;
        $days = Num::parse((string)Request::post('target_days', '45'));
        $tol = Num::parse((string)Request::post('tolerance_days', '5'));
        if ($days <= 0) { Flash::error('Target hari harus lebih besar dari nol.'); $this->back('/acp/target'); }

        Database::i()->exec(
            'INSERT INTO acp_targets (scope, scope_id, period_year, period_month, target_days, tolerance_days, notes, created_by)
             VALUES (:s,:si,:y,:m,:d,:t,:n,:u)
             ON DUPLICATE KEY UPDATE target_days=VALUES(target_days), tolerance_days=VALUES(tolerance_days),
                                     notes=VALUES(notes), deleted_at=NULL',
            ['s' => $scope, 'si' => $scopeId, 'y' => $year, 'm' => $month, 'd' => $days, 't' => $tol,
             'n' => mb_substr((string)Request::post('notes', ''), 0, 255) ?: null, 'u' => Auth::id() ?: null]
        );
        Audit::log('acp', 'update', 'acp_target', null, "Target ACP $scope disimpan: $days hari (tahun $year)");
        Flash::success('Target ACP berhasil disimpan.');
        $this->redirect('/acp/target?tahun=' . $year);
    }

    public function deleteTarget(): void
    {
        $id = Request::int('id');
        Database::i()->exec('UPDATE acp_targets SET deleted_at = NOW() WHERE id = ?', [$id]);
        Audit::log('acp', 'delete', 'acp_target', $id, 'Target ACP dihapus');
        Flash::success('Target ACP dihapus.');
        $this->back('/acp/target');
    }
}
