<?php

namespace App\Commands;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
use App\Models\PayPalPaymentModel;
use App\Models\PaymentModel;
use App\Models\UserModel;
use App\Models\ConfigurationModel;
use App\Models\InvoiceModel;
use App\Models\StudentModel;
use App\Models\EnrollmentModel;

class SyncPaypalPayments extends BaseCommand
{
    protected $group       = 'Payments';
    protected $name        = 'payments:sync-paypal';
    protected $description = 'Sync PayPal payments to internal payments table from paypal_payments';
    protected $configModel;
    protected $semester;
    protected $schoolYear;
    protected $paypalModel;
    protected $paymentModel;
    protected $userModel;
    protected $invoiceModel;
    protected $studentModel;
    protected $enrollmentModel;

    public function __construct()
    {
        $this->configModel = new ConfigurationModel();
        $this->paypalModel    = new PayPalPaymentModel();
        $this->paymentModel   = new PaymentModel();
        $this->userModel      = new UserModel();
        $this->invoiceModel   = new InvoiceModel();
        $this->studentModel = new StudentModel();
        $this->enrollmentModel = new EnrollmentModel();

        $this->semester = $this->configModel->getConfig('semester');
        $this->schoolYear = $this->configModel->getConfig('school_year');
    }

    public function run(array $params)
    {
        $dryRun     = CLI::getOption('dry-run');
        $reportOnly = CLI::getOption('report-only');
        $mode       = $reportOnly ? 'REPORT-ONLY' : ($dryRun ? 'DRY-RUN' : 'LIVE');

        $paypalEntries = $this->paypalModel
            ->where('status', 'COMPLETED')
            ->where('synced', 0)
            ->where('sync_attempts <', 3)
            ->where('transaction_id IS NOT NULL')
            ->findAll();

        $syncedCount = 0;
        $failed = [];

        foreach ($paypalEntries as $entry) {
            $parentId = null;
            $invoiceId = 0;

            $users = $this->userModel->getUsersBySchoolId($entry['parent_school_id']);
            $user = $users[0] ?? null;

            // Always increment sync_attempts unless report-only
            if (!$reportOnly) {
                $this->paypalModel->update($entry['id'], [
                    'sync_attempts' => $entry['sync_attempts'] + 1
                ]);
            }

            if ($user) {
                $parentId = $user['id'];

                $invoice = $this->invoiceModel->getInvoicesByParentId($parentId, $this->schoolYear);

                if (!$reportOnly && !$dryRun) {
                    if ($invoice) {
                        $invoiceId = $invoice['id'];

                        $success = $this->processPayment(
                            $invoiceId,
                            $entry['amount'],
                            'PayPal',
                            null,
                            $entry['transaction_id'],
                            date('Y-m-d', strtotime($entry['created_at'])),
                            $this->schoolYear,
                            $this->semester
                        );

                        if (!$success) {
                            $failed[] = $entry['transaction_id'];
                            continue;
                        }
                    } else {
                        $this->paymentModel->insert([
                            'parent_id'              => $parentId,
                            'invoice_id'             => 0,
                            'total_amount'           => $entry['amount'],
                            'paid_amount'            => $entry['amount'],
                            'balance'                => 0.00,
                            'number_of_installments' => 1,
                            'transaction_id'         => $entry['transaction_id'],
                            'payment_method'         => 'PayPal',
                            'payment_date'           => date('Y-m-d', strtotime($entry['created_at'])),
                            'school_year'            => $this->schoolYear,
                            'semester'               => $this->semester,
                            'status'                 => 'Completed',
                            'updated_by'             => null,
                        ]);
                    }

                    // Mark as synced only in LIVE mode
                    $this->paypalModel->update($entry['id'], ['synced' => 1]);
                }

                $syncedCount++;
            } else {
                log_message('error', "[PAYPAL SYNC FAILED] No user found for parent_school_id: {$entry['parent_school_id']}");
                $failed[] = $entry['transaction_id'];
            }
        }

        // === Logging ===
        log_message('info', "[$mode] PAYPAL SYNC: $syncedCount processed.");
        if (!empty($failed)) {
            log_message('error', "[$mode] PAYPAL SYNC Failed: " . implode(', ', $failed));
        }

        // === CLI Output ===
        CLI::write("[$mode] $syncedCount PayPal payments processed.", 'green');
        if (!empty($failed)) {
            CLI::error("[$mode] Failed transactions: " . implode(', ', $failed));
        }

        // === Email Report: Only if there's any update ===
        if ($syncedCount > 0 || !empty($failed)) {
            helper('email');
            $email = \Config\Services::email();
            $email->setTo('support@alrahmaisgl.org');
            $email->setFrom('no-parentsreply@alrahmaisgl.org', 'PayPal Sync Report');
            $email->setSubject("[$mode] PayPal Sync Report - " . date('Y-m-d H:i'));

            $body = "PayPal Sync Mode: $mode\n\n";
            $body .= "$syncedCount PayPal payments processed.\n\n";

            if (!empty($failed)) {
                $body .= count($failed) . " failed transactions:\n";
                $body .= implode("\n", $failed);
            } else {
                $body .= "No failed transactions.\n";
            }

            $email->setMessage(nl2br($body));

            if ($email->send()) {
                CLI::write("[$mode] Email report sent successfully.", 'yellow');
            } else {
                CLI::error("[$mode] Failed to send email report.");
                log_message('error', 'Email send error: ' . $email->printDebugger(['headers']));
            }
        } else {
            log_message('info', "[$mode] No PayPal sync updates. Email not sent.");
            CLI::write("[$mode] No changes to report. Email not sent.", 'blue');
        }
    }

    private function processPayment($invoiceId, $amount, $paymentMethod, $checkFile = null, $transactionId = null, $paymentDate = null, $schoolYear = null, $semester = null)
    {
        $invoice = $this->invoiceModel->find($invoiceId);
        if (!$invoice) {
            return false;
        }

        $transactionId = $transactionId ?? 'INV-' . $invoiceId . '-' . time();
        $paymentDate   = $paymentDate ?? date('Y-m-d');

        $newPaid    = $invoice['paid_amount'] + $amount;
        $newBalance = $invoice['balance'] - $amount;

        $invoiceUpdateData = [
            'paid_amount' => $newPaid,
            'balance'     => $newBalance,
            'status'      => ($newBalance <= 0) ? 'Paid' : $invoice['status'],
        ];

        if (!$this->invoiceModel->update($invoiceId, $invoiceUpdateData)) {
            return false;
        }

        $this->paymentModel->insert([
            'parent_id'              => $invoice['parent_id'],
            'invoice_id'             => $invoiceId,
            'total_amount'           => $invoice['total_amount'],
            'paid_amount'            => $amount,
            'balance'                => $newBalance,
            'number_of_installments' => 1,
            'transaction_id'         => $transactionId,
            'payment_method'         => $paymentMethod,
            'payment_date'           => $paymentDate,
            'status'                 => ($newBalance <= 0) ? 'Full' : 'Partial',
            'check_file'             => $checkFile,
            'updated_by'             => null, // Avoid using session()->get() in CLI
            'school_year'            => $schoolYear,
            'semester'               => $semester
        ]);

        $this->updateEnrollmentStatusIfPaid($invoiceId, $schoolYear);
        return true;
    }

    private function updateEnrollmentStatusIfPaid($invoiceId, $schoolYear)
    {
        $invoice = $this->invoiceModel->find($invoiceId);
        if (!$invoice || $invoice['balance'] > 0) {
            return;
        }

        $students = $this->studentModel->where('parent_id', $invoice['parent_id'])
            ->where('school_year', $schoolYear)
            ->findAll();

        foreach ($students as $student) {
            $this->enrollmentModel->set(['enrollment_status' => 'enrolled'])
                ->where('student_id', $student['id'])
                ->update();
        }
    }
}
