<?php

namespace App\Controllers\Api;

use App\Models\PaymentTransModel;
use App\Models\PaymentAnnualModel;
use App\Models\MemberModel;

class PaymentTransController extends ApiController
{
    protected $paymentTransModel;
    protected $paymentAnnualModel;
    protected $memberModel;

    public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
    {
        parent::initController($request, $response, $logger);
        
        try {
            $this->paymentTransModel = new PaymentTransModel();
            $this->paymentAnnualModel = new PaymentAnnualModel();
            $this->memberModel = new MemberModel();
        } catch (\Exception $e) {
            log_message('error', 'PaymentTransController init error: ' . $e->getMessage());
        }
    }

    public function index()
    {
        if (!$this->hasAnyRole(['admin', 'finance'])) {
            return $this->respond(['error' => 'Forbidden'], 403);
        }

        $page = (int) $this->request->getGet('page') ?? 1;
        $limit = (int) $this->request->getGet('limit') ?? 20;
        $status = $this->request->getGet('status');

        $query = $this->paymentTransModel;
        if ($status) {
            $query = $query->where('status', $status);
        }

        $transactions = $query->paginate($limit, 'default', $page);

        return $this->respond([
            'transactions' => $transactions,
            'page' => $page,
            'limit' => $limit,
        ]);
    }

    public function getByMember($memberId)
    {
        if (!$this->isAuthenticated()) {
            return $this->respond(['error' => 'Unauthorized'], 401);
        }

        $member = $this->memberModel->find($memberId);
        if (!$member) {
            return $this->respondNotFound();
        }

        $transactions = $this->paymentTransModel->getTransactionByMember($memberId);

        return $this->respond(['transactions' => $transactions]);
    }

    public function create()
    {
        if (!$this->hasRole('finance')) {
            return $this->respond(['error' => 'Forbidden'], 403);
        }

        if (!$this->request->is('post')) {
            return $this->respondBadRequest('Invalid request method');
        }

        $data = $this->request->getJSON();

        if (!isset($data->transaction_no) || !isset($data->amount) || !isset($data->payment_date)) {
            return $this->respondValidationError([
                'transaction_no' => 'Transaction number required',
                'amount' => 'Amount required',
                'payment_date' => 'Payment date required',
            ]);
        }

        $memberIdentifier = $data->member_id ?? $data->reference_no ?? null;
        if (!$memberIdentifier) {
            return $this->respondValidationError(['member_identifier' => 'Member identification required']);
        }

        $member = null;
        if (is_numeric($memberIdentifier)) {
            $member = $this->memberModel->find($memberIdentifier);
        } else {
            $invoice = $this->paymentAnnualModel->where('reference_no', $memberIdentifier)->first();
            if ($invoice) {
                $member = $this->memberModel->find($invoice['member_id']);
            }
        }

        $memberId = $member ? $member['id'] : null;

        $transactionData = [
            'member_id' => $memberId,
            'transaction_no' => $data->transaction_no,
            'amount' => $data->amount,
            'payment_method' => $data->payment_method ?? 'bank_transfer',
            'bank_name' => $data->bank_name ?? null,
            'bank_ref' => $data->bank_ref ?? null,
            'payment_date' => $data->payment_date,
            'status' => 'pending',
            'notes' => $data->notes ?? null,
        ];

        if (!$this->paymentTransModel->insert($transactionData)) {
            return $this->respondBadRequest('Failed: ' . implode(', ', $this->paymentTransModel->errors()));
        }

        $transactionId = $this->paymentTransModel->insertID();
        $this->logAudit('create', 'payment_trans', $transactionId, null, $transactionData);

        $matched = false;
        if ($memberId) {
            $matched = $this->attemptMatch($transactionId);
        }

        return $this->respondCreated([
            'transactionId' => $transactionId,
            'matched' => $matched,
            'message' => 'Transaction recorded' . ($matched ? ' and matched' : ''),
        ]);
    }

    public function show($id)
    {
        if (!$this->isAuthenticated()) {
            return $this->respond(['error' => 'Unauthorized'], 401);
        }

        $transaction = $this->paymentTransModel->find($id);

        if (!$transaction) {
            return $this->respondNotFound();
        }

        return $this->respond($transaction);
    }

    public function update($id)
    {
        if (!$this->hasRole('finance')) {
            return $this->respond(['error' => 'Forbidden'], 403);
        }

        if (!$this->request->is('put')) {
            return $this->respondBadRequest('Invalid request method');
        }

        $transaction = $this->paymentTransModel->find($id);
        if (!$transaction) {
            return $this->respondNotFound();
        }

        $data = $this->request->getJSON();

        $updateData = [];
        if (isset($data->status)) $updateData['status'] = $data->status;
        if (isset($data->notes)) $updateData['notes'] = $data->notes;

        if ($this->paymentTransModel->update($id, $updateData)) {
            $this->logAudit('update', 'payment_trans', $id, $transaction, $updateData);
            return $this->respondUpdated(['message' => 'Transaction updated']);
        }

        return $this->respondBadRequest('Failed to update transaction');
    }

    public function delete($id)
    {
        if (!$this->hasRole('finance')) {
            return $this->respond(['error' => 'Forbidden'], 403);
        }

        $transaction = $this->paymentTransModel->find($id);
        if (!$transaction) {
            return $this->respondNotFound();
        }

        // Don't allow deletion if already matched
        if ($transaction['payment_annual_id'] !== null) {
            return $this->respondBadRequest('Cannot delete matched transaction');
        }

        if ($this->paymentTransModel->delete($id)) {
            $this->logAudit('delete', 'payment_trans', $id, $transaction, null);
            return $this->respondDeleted();
        }

        return $this->respondBadRequest('Failed to delete transaction');
    }

    public function getUnmatched()
    {
        if (!$this->hasRole('finance')) {
            return $this->respond(['error' => 'Forbidden'], 403);
        }

        $unmatched = $this->paymentTransModel->getUnmatchedTransactions();

        return $this->respond(['transactions' => $unmatched]);
    }

    public function match($transactionId, $invoiceId)
    {
        if (!$this->hasRole('finance')) {
            return $this->respond(['error' => 'Forbidden'], 403);
        }

        if (!$this->request->is('post')) {
            return $this->respondBadRequest('Invalid request method');
        }

        $transaction = $this->paymentTransModel->find($transactionId);
        if (!$transaction) {
            return $this->respond(['error' => 'Transaction not found'], 404);
        }

        $invoice = $this->paymentAnnualModel->find($invoiceId);
        if (!$invoice) {
            return $this->respond(['error' => 'Invoice not found'], 404);
        }

        // Check if amounts match
        if ($transaction['amount'] != $invoice['amount']) {
            return $this->respond([
                'error' => 'Amount mismatch',
                'transaction_amount' => $transaction['amount'],
                'invoice_amount' => $invoice['amount']
            ], 400);
        }

        // Update transaction
        $this->paymentTransModel->matchWithInvoice($transactionId, $invoiceId);

        // Update invoice status
        $this->paymentAnnualModel->update($invoiceId, ['status' => 'paid']);

        $this->logAudit('update', 'payment_trans', $transactionId, $transaction, [
            'payment_annual_id' => $invoiceId,
            'status' => 'matched'
        ]);

        return $this->respond(['message' => 'Transaction matched successfully']);
    }

    public function unmatch($transactionId)
    {
        if (!$this->hasRole('finance')) {
            return $this->respond(['error' => 'Forbidden'], 403);
        }

        if (!$this->request->is('post')) {
            return $this->respondBadRequest('Invalid request method');
        }

        $transaction = $this->paymentTransModel->find($transactionId);
        if (!$transaction) {
            return $this->respondNotFound();
        }

        if ($transaction['payment_annual_id'] === null) {
            return $this->respond(['error' => 'Transaction not matched'], 400);
        }

        $invoiceId = $transaction['payment_annual_id'];

        // Update transaction
        $this->paymentTransModel->update($transactionId, [
            'payment_annual_id' => null,
            'status' => 'confirmed'
        ]);

        // Revert invoice status
        $this->paymentAnnualModel->update($invoiceId, ['status' => 'pending']);

        $this->logAudit('update', 'payment_trans', $transactionId, $transaction, [
            'payment_annual_id' => null,
            'status' => 'confirmed'
        ]);

        return $this->respond(['message' => 'Transaction unmatched']);
    }

    public function getMatching()
    {
        if (!$this->hasRole('finance')) {
            return $this->respond(['error' => 'Forbidden'], 403);
        }

        // Get pending invoices and unmatched transactions
        $pendingInvoices = $this->paymentAnnualModel->getOutstandingInvoices();
        $unmatchedTransactions = $this->paymentTransModel->getUnmatchedTransactions();

        // Find possible matches (by amount)
        $matches = [];
        foreach ($unmatchedTransactions as $trans) {
            foreach ($pendingInvoices as $invoice) {
                if ($trans['amount'] == $invoice['amount'] && $trans['member_id'] == $invoice['member_id']) {
                    $matches[] = [
                        'transaction' => $trans,
                        'invoice' => $invoice,
                        'match_score' => 100
                    ];
                }
            }
        }

        return $this->respond([
            'matches' => $matches,
            'pending_invoices' => $pendingInvoices,
            'unmatched_transactions' => $unmatchedTransactions,
        ]);
    }

    public function getStats()
    {
        if (!$this->hasAnyRole(['admin', 'finance'])) {
            return $this->respond(['error' => 'Forbidden'], 403);
        }

        $totalTransactions = $this->db->table('payment_trans')->countAllResults();
        $matchedTransactions = $this->db->table('payment_trans')->where('status', 'matched')->countAllResults();
        $unmatchedTransactions = $this->db->table('payment_trans')
            ->whereIn('status', ['pending', 'confirmed'])
            ->countAllResults();

        $totalAmountRow = $this->db->table('payment_trans')->selectSum('amount')->get()->getRowArray();
        $totalAmount = (float) ($totalAmountRow['amount'] ?? 0);
        $matchedAmountRow = $this->db->table('payment_trans')
            ->where('status', 'matched')
            ->selectSum('amount')
            ->get()
            ->getRowArray();
        $matchedAmount = (float) ($matchedAmountRow['amount'] ?? 0);

        return $this->respond([
            'total_transactions' => $totalTransactions,
            'matched_transactions' => $matchedTransactions,
            'unmatched_transactions' => $unmatchedTransactions,
            'matched_percentage' => ($totalTransactions > 0) ? round(($matchedTransactions / $totalTransactions) * 100, 2) : 0,
            'total_amount' => $totalAmount,
            'matched_amount' => $matchedAmount,
        ]);
    }

    private function attemptMatch($transactionId)
    {
        $transaction = $this->paymentTransModel->find($transactionId);
        
        // Try to find matching invoice
        $matchingInvoice = $this->paymentAnnualModel
            ->where('member_id', $transaction['member_id'])
            ->where('amount', $transaction['amount'])
            ->where('status', 'pending')
            ->first();

        if ($matchingInvoice) {
            $this->paymentTransModel->matchWithInvoice($transactionId, $matchingInvoice['id']);
            $this->paymentAnnualModel->update($matchingInvoice['id'], ['status' => 'paid']);
            return true;
        }

        return false;
    }
}
