<?php

namespace App\Controllers;

use App\Models\AiCorporateSummaryModel;
use App\Models\CorporateAccountModel;
use App\Models\RatePlanModel;

/**
 * Manager-only. Minimal corporate billing accounts — see
 * CreateCorporateAccountsTable for why this is deliberately small.
 */
class CorporateAccountController extends BaseController
{
    public function index()
    {
        $term  = trim((string) $this->request->getGet('q'));
        $model = new CorporateAccountModel();

        $accounts = $term !== ''
            ? $model->search($term)->orderBy('company_name')->findAll()
            : $model->orderBy('company_name')->findAll();

        return view('corporate_accounts/index', [
            'pageTitle' => 'Corporate Accounts',
            'accounts'  => $accounts,
            'term'      => $term,
        ]);
    }

    public function new()
    {
        return view('corporate_accounts/form', [
            'pageTitle' => 'New Corporate Account',
            'account'   => null,
            'ratePlans' => (new RatePlanModel())->where('is_active', 1)->orderBy('name')->findAll(),
        ]);
    }

    public function create()
    {
        $model = new CorporateAccountModel();
        $data  = $this->collectInput();

        if (! $model->insert($data)) {
            return $this->redirectWithModelErrors($model);
        }

        $this->logActivity('corporate_accounts', 'Created corporate account "' . $data['company_name'] . '".');

        return redirect()->to('corporate-accounts/' . $model->getInsertID())->with('success', 'Corporate account created.');
    }

    public function show(int $id)
    {
        $account = (new CorporateAccountModel())->find($id);

        if ($account === null) {
            return redirect()->to('corporate-accounts')->with('error', 'Corporate account not found.');
        }

        return view('corporate_accounts/show', [
            'pageTitle' => $account->company_name,
            'account'   => $account,
            'thisMonth' => date('Y-m'),
            'ratePlan'  => $account->default_rate_plan_id ? (new RatePlanModel())->find($account->default_rate_plan_id) : null,
        ]);
    }

    public function edit(int $id)
    {
        $account = (new CorporateAccountModel())->find($id);

        if ($account === null) {
            return redirect()->to('corporate-accounts')->with('error', 'Corporate account not found.');
        }

        return view('corporate_accounts/form', [
            'pageTitle' => 'Edit Corporate Account',
            'account'   => $account,
            'ratePlans' => (new RatePlanModel())->where('is_active', 1)->orderBy('name')->findAll(),
        ]);
    }

    public function update(int $id)
    {
        $model = new CorporateAccountModel();

        if ($model->find($id) === null) {
            return redirect()->to('corporate-accounts')->with('error', 'Corporate account not found.');
        }

        $data = $this->collectInput();

        if (! $model->update($id, $data)) {
            return $this->redirectWithModelErrors($model);
        }

        $this->logActivity('corporate_accounts', 'Updated corporate account "' . $data['company_name'] . '".');

        return redirect()->to('corporate-accounts/' . $id)->with('success', 'Corporate account updated.');
    }

    /**
     * Monthly statement PDF — aggregates every charge on a folio tagged
     * to this account, dated within the given month (default: this month).
     */
    public function statement(int $id)
    {
        $account = (new CorporateAccountModel())->find($id);

        if ($account === null) {
            return redirect()->to('corporate-accounts')->with('error', 'Corporate account not found.');
        }

        $month = $this->request->getGet('month') ?: date('Y-m');

        if (! preg_match('/^\d{4}-\d{2}$/', $month)) {
            return redirect()->to('corporate-accounts/' . $id)->with('error', 'Invalid month.');
        }

        $monthStart = $month . '-01';
        $monthEnd   = date('Y-m-d', strtotime($monthStart . ' +1 month'));

        $model   = new CorporateAccountModel();
        $charges = $model->chargesForMonth($id, $monthStart, $monthEnd);
        $total   = array_reduce($charges, static fn ($carry, $c) => $carry + (float) $c->amount, 0.0);

        $html = view('invoices/corporate_statement', [
            'account'     => $account,
            'charges'     => $charges,
            'totalAmount' => number_format($total, 2, '.', ''),
            'monthLabel'  => date('F Y', strtotime($monthStart)),
            'tenant'      => service('tenantContext')->getTenant(),
            'issuedAt'    => date('Y-m-d H:i'),
            'aiSummary'   => $this->corporateHealthSummary($id, $month, $monthStart, $monthEnd, $total),
        ]);

        $pdf = service('pdfService')->renderHtml($html);

        $this->logActivity('corporate_accounts', "Generated {$month} statement for \"{$account->company_name}\".");

        return $this->response
            ->setHeader('Content-Type', 'application/pdf')
            ->setHeader('Content-Disposition', "inline; filename=\"statement-{$account->id}-{$month}.pdf\"")
            ->setBody($pdf);
    }

    /**
     * Cached per (account, month) — see AiCorporateSummaryModel/
     * CreateAiCorporateSummariesTable's doc comment for why: a statement
     * can be re-downloaded any number of times, and only the first
     * generation for a given month should call Claude. Compares this
     * month's real total (already computed by the caller) against the
     * prior month's real total via the exact same CorporateAccountModel::
     * chargesForMonth() the statement itself uses — never a separately
     * computed figure. Returns null (no note shown) if the feature is
     * off, rather than blocking statement generation on an AI call.
     */
    private function corporateHealthSummary(int $accountId, string $month, string $monthStart, string $monthEnd, float $currentTotal): ?string
    {
        if (service('settings')->get('ai.corporate_summary_enabled', '1') !== '1') {
            return null;
        }

        $summaries = new AiCorporateSummaryModel();
        $cached    = $summaries->forAccountMonth($accountId, $month);

        if ($cached !== null) {
            return $cached->summary_text;
        }

        $priorMonthStart = date('Y-m-01', strtotime($monthStart . ' -1 month'));
        $priorMonth      = date('Y-m', strtotime($priorMonthStart));
        $priorCharges    = (new CorporateAccountModel())->chargesForMonth($accountId, $priorMonthStart, $monthStart);
        $priorTotal      = array_reduce($priorCharges, static fn ($carry, $c) => $carry + (float) $c->amount, 0.0);

        $data = [
            'this_month'  => ['month' => $month, 'total' => round($currentTotal, 2)],
            'prior_month' => ['month' => $priorMonth, 'total' => round($priorTotal, 2)],
        ];

        $systemPrompt = 'You write a short (1-2 sentence) trend note for a hotel\'s corporate billing account monthly '
            . 'statement, comparing this month\'s real total spend to the prior month\'s real total spend. Only ever '
            . 'reference the two totals given to you — never invent a figure, a reason, or a trend not evidenced by '
            . 'these two numbers. If the prior month has no charges at all, say the comparison isn\'t meaningful '
            . 'rather than computing a misleading percentage.';

        $result = service('claudeService')->chat(
            'corporate_summary',
            $systemPrompt,
            [['role' => 'user', 'content' => json_encode($data)]],
            [],
            null,
            'corporate_account',
            $accountId,
            $this->currentUserId(),
        );

        if (! $result['success']) {
            return null; // statement still generates fine without the note.
        }

        $summaries->insert([
            'corporate_account_id' => $accountId,
            'month'                => $month,
            'summary_text'         => $result['text'],
            'data_snapshot'        => json_encode($data),
        ]);

        return $result['text'];
    }

    /** Used by CorporateAccountController's new-account form's inline search, and the folio "bill to" picker. */
    public function lookup()
    {
        $term = (string) $this->request->getGet('q');

        if (trim($term) === '') {
            return $this->response->setJSON(['results' => []]);
        }

        $accounts = (new CorporateAccountModel())->search($term)->limit(10)->findAll();

        return $this->response->setJSON([
            'results' => array_map(static fn ($a) => ['id' => $a->id, 'company_name' => $a->company_name], $accounts),
        ]);
    }

    private function collectInput(): array
    {
        $ratePlanId = (int) $this->request->getPost('default_rate_plan_id');

        return [
            'company_name'          => $this->request->getPost('company_name'),
            'contact_name'          => $this->request->getPost('contact_name') ?: null,
            'billing_address'       => $this->request->getPost('billing_address') ?: null,
            'phone'                 => $this->request->getPost('phone') ?: null,
            'email'                 => $this->request->getPost('email') ?: null,
            'default_rate_plan_id'  => $ratePlanId > 0 ? $ratePlanId : null,
        ];
    }
}
