<?php

namespace App\Controllers;

use App\Core\Controller;
use App\Helpers\Auth;
use App\Helpers\PaymentGateway;
use App\Helpers\Url;
use App\Models\Contribution;
use App\Models\ContributionType;
use App\Models\Receipt;
use App\Models\Setting;
use App\Models\AuditLog;
use App\Models\LoanRepayment;
use App\Models\Loan;

class PaymentController extends Controller
{
    public function __construct()
    {
        parent::__construct();
        Auth::requireLogin();
    }

    public function make()
    {
        $userId = Auth::id();
        $model = new Contribution();
        $typeModel = new ContributionType();
        $types = $typeModel->getActive();
        $obligations = $model->getObligations($userId);
        $summary = $model->getMemberSummary($userId);
        $gateways = PaymentGateway::getAvailableGateways();

        $totalArrears = 0;
        $unpaidMonths = [];
        foreach ($obligations as $o) {
            if (!$o->is_fully_paid) {
                $totalArrears += $o->balance;
                $unpaidMonths[] = $o;
            }
        }

        $this->view('payment/make', [
            'obligations' => $unpaidMonths,
            'totalArrears' => $totalArrears,
            'summary' => $summary,
            'types' => $types,
            'gateways' => $gateways,
        ]);
    }

    public function init()
    {
        $userId = Auth::id();
        $amount = (float)($_POST['amount'] ?? 0);
        $contributionTypeId = (int)($_POST['contribution_type_id'] ?? 0);
        $paidMonth = $_POST['paid_month'] ?? date('Y-m');
        $gateway = $_POST['gateway'] ?? '';
        $description = $_POST['description'] ?? 'Membership Contribution';

        if ($amount <= 0) {
            $_SESSION['error'] = 'Invalid payment amount';
            $this->redirect('/payment/make');
        }

        if (!in_array($gateway, ['paystack', 'hubtel'])) {
            $_SESSION['error'] = 'Invalid payment gateway';
            $this->redirect('/payment/make');
        }

        if (!PaymentGateway::isEnabled($gateway)) {
            $_SESSION['error'] = 'Selected payment gateway is not enabled';
            $this->redirect('/payment/make');
        }

        $reference = 'GAS-' . strtoupper(substr($gateway, 0, 2)) . '-' . date('YmdHis') . '-' . $userId . '-' . mt_rand(1000, 9999);

        $callbackUrl = Url::to('/payment/callback?gateway=' . $gateway . '&ref=' . $reference);

        $setting = new Setting();
        $email = $_SESSION['user_email'] ?? '';

        $result = null;
        if ($gateway === 'paystack') {
            $result = PaymentGateway::initPaystackPayment($email, $amount, $reference, $callbackUrl);
        } elseif ($gateway === 'hubtel') {
            $result = PaymentGateway::initHubtelPayment($email, $amount, $reference, $callbackUrl, $description);
        }

        if (!$result || !$result['success']) {
            $_SESSION['error'] = 'Payment initialization failed: ' . ($result['message'] ?? 'Unknown error');
            $this->redirect('/payment/make');
        }

        $contributionModel = new Contribution();
        $existingBal = $contributionModel->getObligationBalance($userId, $contributionTypeId, $paidMonth);

        $contributionId = $contributionModel->create([
            'user_id' => $userId,
            'contribution_type_id' => $contributionTypeId ?: 1,
            'amount' => $amount,
            'total_amount' => $existingBal->total ?: $amount,
            'balance' => $amount,
            'payment_method' => $gateway,
            'payment_gateway' => $gateway,
            'gateway_ref' => $reference,
            'payment_date' => date('Y-m-d'),
            'paid_month' => $paidMonth,
            'status' => 'pending',
            'notes' => 'Online payment via ' . ucfirst($gateway) . ' (pending)',
            'processed_by' => $userId,
        ]);

        $_SESSION['pending_payment'] = [
            'contribution_id' => $contributionId,
            'reference' => $reference,
            'gateway' => $gateway,
        ];

        $this->redirect($result['authorization_url']);
    }

    public function callback()
    {
        $gateway = $_GET['gateway'] ?? '';
        $reference = $_GET['ref'] ?? $_GET['reference'] ?? '';

        if (!$gateway || !$reference) {
            $this->view('payment/callback', ['success' => false, 'message' => 'Missing payment parameters']);
            return;
        }

        $result = null;
        if ($gateway === 'paystack') {
            $result = PaymentGateway::verifyPaystackPayment($reference);
        } elseif ($gateway === 'hubtel') {
            $result = PaymentGateway::verifyHubtelPayment($reference);
        } else {
            $this->view('payment/callback', ['success' => false, 'message' => 'Unknown gateway']);
            return;
        }

        $contributionModel = new Contribution();
        $contributions = $contributionModel->raw(
            "SELECT * FROM contributions WHERE gateway_ref = ? ORDER BY id DESC LIMIT 1",
            [$reference]
        );

        if (empty($contributions)) {
            // If not a contribution, check if this reference maps to a loan repayment
            if (str_starts_with($reference, 'loan_lr_')) {
                // expected format: loan_lr_{repaymentId}_{timestamp}
                $parts = explode('_', $reference);
                $repaymentId = $parts[2] ?? null;
                if ($repaymentId) {
                    $loanRepModel = new LoanRepayment();
                    if ($result['success']) {
                        $paidAmount = $result['amount'];
                        $loanRepModel->recordPayment((int)$repaymentId, $paidAmount, $gateway, $reference, 'Online payment');

                        // Update loan status if fully paid
                        $repRow = $loanRepModel->find((int)$repaymentId);
                        $loanId = $repRow->loan_id ?? 0;
                        $totals = $loanRepModel->getTotalsByLoan($loanId);
                        $loanModel = new Loan();
                        if ($totals && $totals->total_paid >= $totals->total_due) {
                            $loanModel->update($loanId, ['status' => 'completed']);
                        }

                        $audit = new AuditLog();
                        $audit->log(0, 'loan.repayment', 'loan_repayments', $repaymentId, "Online repayment via {$gateway}: GHS {$paidAmount} (ref: {$reference})");

                        $this->view('payment/callback', ['success' => true, 'message' => 'Loan repayment recorded', 'reference' => $reference]);
                        return;
                    } else {
                        $this->view('payment/callback', ['success' => false, 'message' => $result['message'] ?? 'Loan payment verification failed', 'reference' => $reference]);
                        return;
                    }
                }
            }

            $this->view('payment/callback', ['success' => false, 'message' => 'Payment record not found']);
            return;
        }

        $contribution = $contributions[0];

        if ($result['success']) {
            $newBalance = max(0, ($contribution->total_amount ?? $result['amount']) - $result['amount']);
            $status = ($newBalance <= 0) ? 'completed' : 'partial';

            $contributionModel->update($contribution->id, [
                'status' => $status,
                'balance' => $newBalance,
                'gateway_response' => json_encode($result['raw'] ?? []),
            ]);

            if ($contribution->paid_month && $contribution->contribution_type_id) {
                $contributionModel->updateBalanceForObligation(
                    $contribution->user_id,
                    $contribution->contribution_type_id,
                    $contribution->paid_month
                );
            }

            $receiptId = null;
            if ($status === 'completed') {
                $receiptModel = new Receipt();
                $receiptId = $receiptModel->create([
                    'contribution_id' => $contribution->id,
                    'receipt_number' => $receiptModel->generateNumber(),
                    'issued_date' => date('Y-m-d'),
                    'issued_by' => $contribution->user_id,
                ]);
            }

            $audit = new AuditLog();
            $audit->log($contribution->user_id, 'payment.completed', 'contributions', $contribution->id,
                "Online payment via {$gateway}: GHS {$result['amount']} (ref: {$reference})");

            if (isset($_SESSION['pending_payment'])) {
                unset($_SESSION['pending_payment']);
            }

            $this->view('payment/callback', [
                'success' => true,
                'message' => 'Payment completed successfully',
                'amount' => $result['amount'],
                'reference' => $reference,
                'gateway' => $gateway,
                'status' => $status,
                'receiptId' => $receiptId,
                'contributionId' => $contribution->id,
            ]);
        } else {
            $contributionModel->update($contribution->id, [
                'status' => 'failed',
                'gateway_response' => json_encode($result['raw'] ?? []),
            ]);

            $audit = new AuditLog();
            $audit->log($contribution->user_id, 'payment.failed', 'contributions', $contribution->id,
                "Online payment failed via {$gateway}: {$result['message']} (ref: {$reference})");

            $this->view('payment/callback', [
                'success' => false,
                'message' => $result['message'] ?? 'Payment verification failed',
                'reference' => $reference,
            ]);
        }
    }

    public function webhook($params)
    {
        $gateway = $params['gateway'] ?? '';

        if ($gateway === 'paystack') {
            $input = json_decode(file_get_contents('php://input'));
            if (!$input || !isset($input->event)) {
                http_response_code(400);
                echo 'Invalid event';
                return;
            }

            if ($input->event === 'charge.success') {
                $reference = $input->data->reference ?? '';
                $amount = ($input->data->amount ?? 0) / 100;
                // If reference maps to a contribution, update it; else check for loan repayment reference
                $contributionModel = new Contribution();
                $contributions = $contributionModel->raw(
                    "SELECT * FROM contributions WHERE gateway_ref = ? AND status = 'pending' ORDER BY id DESC LIMIT 1",
                    [$reference]
                );

                if (!empty($contributions)) {
                    $c = $contributions[0];
                    $newBalance = max(0, ($c->total_amount ?? $amount) - $amount);
                    $status = ($newBalance <= 0) ? 'completed' : 'partial';

                    $contributionModel->update($c->id, [
                        'status' => $status,
                        'balance' => $newBalance,
                        'gateway_response' => json_encode($input),
                    ]);

                    if ($c->paid_month && $c->contribution_type_id) {
                        $contributionModel->updateBalanceForObligation(
                            $c->user_id, $c->contribution_type_id, $c->paid_month
                        );
                    }

                    if ($status === 'completed') {
                        $receiptModel = new Receipt();
                        $receiptModel->create([
                            'contribution_id' => $c->id,
                            'receipt_number' => $receiptModel->generateNumber(),
                            'issued_date' => date('Y-m-d'),
                            'issued_by' => $c->user_id,
                        ]);
                    }
                } elseif (str_starts_with($reference, 'loan_lr_')) {
                    // loan repayment reference
                    $parts = explode('_', $reference);
                    $repaymentId = $parts[2] ?? null;
                    if ($repaymentId) {
                        $loanRepModel = new LoanRepayment();
                        $loanRepModel->recordPayment((int)$repaymentId, $amount, 'paystack', $reference, 'Webhook auto payment');

                        $repRow = $loanRepModel->find((int)$repaymentId);
                        $loanId = $repRow->loan_id ?? 0;
                        $totals = $loanRepModel->getTotalsByLoan($loanId);
                        $loanModel = new Loan();
                        if ($totals && $totals->total_paid >= $totals->total_due) {
                            $loanModel->update($loanId, ['status' => 'completed']);
                        }

                        $audit = new AuditLog();
                        $audit->log(0, 'loan.repayment', 'loan_repayments', $repaymentId, "Webhook repayment: GHS {$amount} (ref: {$reference})");
                    }
                }
            }

            http_response_code(200);
            echo 'OK';
        } elseif ($gateway === 'hubtel') {
            $input = json_decode(file_get_contents('php://input'));
            http_response_code(200);
            echo 'OK';
        } else {
            http_response_code(400);
            echo 'Unknown gateway';
        }
    }

    public function receipt($params)
    {
        $id = $params['id'] ?? null;
        $receiptModel = new Receipt();
        $receipt = $receiptModel->getWithDetails($id);

        if (!$receipt) {
            $_SESSION['error'] = 'Receipt not found';
            $this->redirect('/payment/make');
        }

        if (Auth::user()->role !== 'admin' && Auth::id() != $receipt->user_id) {
            $_SESSION['error'] = 'Unauthorized';
            $this->redirect('/payment/make');
        }

        $settingModel = new Setting();
        $receipt->company_name = $settingModel->getValue('receipt_company_name', 'Ghana Anaesthesiologists Society');
        $receipt->company_details = $settingModel->getValue('receipt_company_details', '');

        $this->view('contributions/receipt_download', ['receipt' => $receipt]);
    }
}
