<?php

namespace App\Services\Payments;

use App\Models\Configuration;
use App\Models\Enrollment;
use App\Models\Invoice;
use App\Models\PayPalPayment;
use App\Models\Payment;
use App\Models\Student;
use App\Models\User;
use App\Services\EmailService;
use Illuminate\Support\Facades\Log;

class PaypalPaymentSyncService
{
    public function __construct(private EmailService $emailService)
    {
    }

    public function sync(bool $dryRun = false, bool $reportOnly = false): array
    {
        $mode = $reportOnly ? 'REPORT-ONLY' : ($dryRun ? 'DRY-RUN' : 'LIVE');

        $semester = (string) (Configuration::getConfig('semester') ?? '');
        $schoolYear = (string) (Configuration::getConfig('school_year') ?? '');

        $entries = PayPalPayment::query()
            ->where('status', 'COMPLETED')
            ->where('synced', 0)
            ->where('sync_attempts', '<', 3)
            ->whereNotNull('transaction_id')
            ->get();

        $synced = 0;
        $failed = [];

        foreach ($entries as $entry) {
            if (!$reportOnly) {
                $entry->sync_attempts = (int) $entry->sync_attempts + 1;
                $entry->save();
            }

            $user = User::query()->where('school_id', $entry->parent_school_id)->first();
            if (!$user) {
                $failed[] = (string) $entry->transaction_id;
                Log::error('PayPal sync: no user for parent_school_id', ['parent_school_id' => $entry->parent_school_id]);
                continue;
            }

            $invoice = Invoice::query()
                ->where('parent_id', $user->id)
                ->where('school_year', $schoolYear)
                ->latest('created_at')
                ->first();

            if (!$reportOnly && !$dryRun) {
                if ($invoice) {
                    $ok = $this->applyPayment($invoice, $entry->amount, (string) $entry->transaction_id, $schoolYear, $semester, $entry->created_at);
                    if (!$ok) {
                        $failed[] = (string) $entry->transaction_id;
                        continue;
                    }
                } else {
                    Payment::query()->create([
                        'parent_id' => $user->id,
                        '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' => optional($entry->created_at)->format('Y-m-d'),
                        'school_year' => $schoolYear,
                        'semester' => $semester,
                        'status' => 'Completed',
                        'updated_by' => null,
                    ]);
                }

                $entry->synced = 1;
                $entry->save();
            }

            $synced++;
        }

        $this->sendReport($mode, $synced, $failed);

        return [
            'mode' => $mode,
            'processed' => $synced,
            'failed' => $failed,
        ];
    }

    private function applyPayment(Invoice $invoice, float $amount, string $transactionId, string $schoolYear, string $semester, $createdAt): bool
    {
        $newPaid = (float) $invoice->paid_amount + $amount;
        $newBalance = (float) $invoice->balance - $amount;

        $invoice->paid_amount = $newPaid;
        $invoice->balance = $newBalance;
        if ($newBalance <= 0) {
            $invoice->status = 'Paid';
        }

        if (!$invoice->save()) {
            return false;
        }

        Payment::query()->create([
            'parent_id' => $invoice->parent_id,
            'invoice_id' => $invoice->id,
            'total_amount' => $invoice->total_amount,
            'paid_amount' => $amount,
            'balance' => $newBalance,
            'number_of_installments' => 1,
            'transaction_id' => $transactionId,
            'payment_method' => 'PayPal',
            'payment_date' => $createdAt ? date('Y-m-d', strtotime((string) $createdAt)) : date('Y-m-d'),
            'status' => $newBalance <= 0 ? 'Full' : 'Partial',
            'check_file' => null,
            'updated_by' => null,
            'school_year' => $schoolYear,
            'semester' => $semester,
        ]);

        $this->updateEnrollmentStatusIfPaid($invoice->id, $schoolYear);

        return true;
    }

    private function updateEnrollmentStatusIfPaid(int $invoiceId, string $schoolYear): void
    {
        $invoice = Invoice::query()->find($invoiceId);
        if (!$invoice || (float) $invoice->balance > 0) {
            return;
        }

        $students = Student::query()
            ->where('parent_id', $invoice->parent_id)
            ->where('school_year', $schoolYear)
            ->get();

        foreach ($students as $student) {
            Enrollment::query()
                ->where('student_id', $student->id)
                ->update(['enrollment_status' => 'enrolled']);
        }
    }

    private function sendReport(string $mode, int $processed, array $failed): void
    {
        if ($processed === 0 && empty($failed)) {
            Log::info("[{$mode}] No PayPal sync updates.");
            return;
        }

        $subject = "[{$mode}] PayPal Sync Report - " . now()->format('Y-m-d H:i');
        $body = "PayPal Sync Mode: {$mode}\n\n";
        $body .= "{$processed} PayPal payments processed.\n\n";

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

        $this->emailService->send('support@alrahmaisgl.org', $subject, nl2br($body), 'finance');
    }
}
