<?php

namespace App\Services\School;

use App\Services\ApplicationUrlService;
use App\Services\EmailService;
use App\Services\Notifications\UserNotificationDispatchService;
use Illuminate\Support\Facades\Log;

class PaymentEventService
{
    public function __construct(
        private EmailService $emailService,
        private UserNotificationDispatchService $notifier,
        private ApplicationUrlService $urls,
    ) {
    }

    public function paymentReceived(array $data, array $studentdata = []): array
    {
        $parentName = trim((string) ($data['firstname'] ?? '') . ' ' . (string) ($data['lastname'] ?? ''));

        $fmtMoney = static fn ($v) => '$' . number_format((float) $v, 2);
        $fmtDateTz = static function (?string $s): string {
            if (!$s) {
                return '';
            }
            $dt = new \DateTime($s, new \DateTimeZone('UTC'));
            $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
            $dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC'));
            return $dt->format('m-d-Y h:i A');
        };

        $txid = $data['transaction_id']
            ?? $data['transactionId']
            ?? $data['payment_id']
            ?? $data['id']
            ?? '';

        $methodRaw = $data['payment_method'] ?? ($data['method'] ?? '');
        $method = $methodRaw ? ucfirst((string) $methodRaw) : '';

        $amountPaid = $fmtMoney($data['amount'] ?? 0);
        $preBalance = $fmtMoney($data['pre_balance'] ?? 0);
        $postBalance = $fmtMoney($data['post_balance'] ?? 0);
        $invoiceTotal = $fmtMoney($data['invoice_total'] ?? 0);

        $invoiceDiscountRaw = isset($data['invoice_discount']) ? (float) $data['invoice_discount'] : 0.0;
        $parentYearDiscountTotalRaw = isset($data['parent_year_discount_total']) ? (float) $data['parent_year_discount_total'] : 0.0;

        $emailData = [
            'title' => 'Payment Receipt',
            'parentName' => $parentName,
            'schoolYear' => $data['school_year'] ?? '',
            'semester' => $data['semester'] ?? '',
            'invoiceId' => $data['invoice_id'] ?? null,
            'invoiceNumber' => $data['invoice_number'] ?? null,
            'transactionId' => $txid,
            'paymentDate' => $fmtDateTz($data['payment_date'] ?? null),
            'method' => $method,
            'paymentMethod' => $method,
            'amount' => $amountPaid,
            'invoiceTotal' => $invoiceTotal,
            'preBalance' => $preBalance,
            'postBalance' => $postBalance,
            'checkNumber' => $data['check_number'] ?? null,
            'installmentSeq' => (int) ($data['installment_seq'] ?? 1),
            'invoiceDiscount' => $invoiceDiscountRaw > 0 ? $fmtMoney($invoiceDiscountRaw) : null,
            'parentYearDiscountTotal' => $parentYearDiscountTotalRaw > 0 ? $fmtMoney($parentYearDiscountTotalRaw) : null,
            'portalLink' => $this->urls->webLoginUrl(),
            'students' => $studentdata,
        ];

        $inAppTitle = 'Payment Received';
        $inAppMsg = sprintf(
            'We received %s for Invoice #%s (Installment #%d). New balance: %s. Check your email for details.',
            $emailData['amount'],
            (string) ($emailData['invoiceId'] ?? $emailData['invoiceNumber'] ?? ''),
            (int) $emailData['installmentSeq'],
            $emailData['postBalance']
        );
        $this->notifyUser((int) ($data['user_id'] ?? 0), $inAppTitle, $inAppMsg, 'payments');

        $emailBody = $this->renderEmail('emails/payment_receipt', $emailData, 'Payment Receipt');
        $subject = sprintf(
            'Payment Receipt - Invoice #%s (%s) %s',
            (string) ($emailData['invoiceId'] ?? $emailData['invoiceNumber'] ?? ''),
            $emailData['amount'],
            $txid ? "[TX: {$txid}]" : ''
        );

        return $this->sendEmail((string) ($data['email'] ?? ''), $subject, $emailBody, 'payments');
    }

    public function extraCharge(array $data, array $studentdata = []): array
    {
        $fmtMoney = static fn ($v) => '$' . number_format((float) $v, 2);
        $fmtFromUtc = static function (?string $s, string $fmt = 'm-d-Y h:i A'): string {
            if (!$s) {
                return '';
            }
            try {
                $dt = new \DateTime($s, new \DateTimeZone('UTC'));
                $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
                $dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC'));
                return $dt->format($fmt);
            } catch (\Throwable $e) {
                Log::error('extraCharge date error: ' . $e->getMessage());
                return '';
            }
        };

        $fmtDueLocal = static function (?string $s): string {
            if (!$s) {
                return '';
            }
            try {
                if (strlen($s) <= 10) {
                    $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
                    $dt = \DateTime::createFromFormat('Y-m-d', $s, new \DateTimeZone($tzName ?: 'UTC'));
                    return $dt ? $dt->format('m-d-Y') : '';
                }

                if (preg_match('/(Z|[+\-]\d{2}:\d{2})$/', $s)) {
                    $dt = new \DateTime($s);
                    $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
                    $dt->setTimezone(new \DateTimeZone($tzName ?: 'UTC'));
                    return $dt->format('m-d-Y h:i A');
                }

                $tzName = (string) (config('School')->attendance['timezone'] ?? user_timezone());
                $dt = new \DateTime($s, new \DateTimeZone($tzName ?: 'UTC'));
                return $dt->format('m-d-Y h:i A');
            } catch (\Throwable $e) {
                Log::error('extraCharge due date error: ' . $e->getMessage());
                return '';
            }
        };

        $parentName = trim((string) ($data['firstname'] ?? '') . ' ' . (string) ($data['lastname'] ?? ''));

        $amountSigned = (float) ($data['amount_signed'] ?? 0);
        $amountAbs = (float) ($data['amount_abs'] ?? abs($amountSigned));
        $preBalance = $fmtMoney($data['pre_balance'] ?? 0);
        $postBalance = $fmtMoney($data['post_balance'] ?? 0);
        $invoiceTotal = $fmtMoney($data['invoice_total'] ?? 0);
        $createdAt = $fmtFromUtc($data['created_at'] ?? null);
        $dueDate = $fmtDueLocal($data['due_date'] ?? null);
        $typeLabel = (($data['charge_type'] ?? 'add') === 'add') ? 'Added charge' : 'Deducted amount';
        $amountFmt = $fmtMoney($amountSigned);

        $emailData = [
            'title' => 'Account Charge Update',
            'parentName' => $parentName,
            'schoolYear' => $data['school_year'] ?? '',
            'semester' => $data['semester'] ?? '',
            'invoiceId' => $data['invoice_id'] ?? null,
            'invoiceNumber' => $data['invoice_number'] ?? null,
            'typeLabel' => $typeLabel,
            'chargeTitle' => $data['charge_title'] ?? '',
            'chargeDesc' => $data['charge_desc'] ?? '',
            'chargeType' => $data['charge_type'] ?? 'add',
            'amountSigned' => $amountFmt,
            'amountAbs' => $fmtMoney($amountAbs),
            'invoiceTotal' => $invoiceTotal,
            'preBalance' => $preBalance,
            'postBalance' => $postBalance,
            'createdAt' => $createdAt,
            'dueDate' => $dueDate !== '' ? $dueDate : null,
            'portalLink' => $data['portal_link'] ?? $this->urls->webLoginUrl(),
            'invoiceLink' => $data['invoice_link'] ?? null,
            'students' => $studentdata,
        ];

        $inAppTitle = 'Account Updated';
        $inAppMsg = sprintf(
            '%s: %s (%s). New balance: %s.',
            $typeLabel,
            $emailData['chargeTitle'],
            $emailData['amountSigned'],
            $emailData['postBalance']
        );
        $this->notifyUser((int) ($data['user_id'] ?? 0), $inAppTitle, $inAppMsg, 'billing');

        $subject = sprintf(
            'Charge Update - Invoice #%s (%s)',
            (string) ($emailData['invoiceId'] ?? $emailData['invoiceNumber'] ?? ''),
            $emailData['amountSigned']
        );

        $body = $this->renderEmail('emails/extra_charge_notice', $emailData, 'Account Charge Update');
        return $this->sendEmail((string) ($data['email'] ?? ''), $subject, $body, 'billing');
    }

    private function notifyUser(int $userId, string $title, string $message, string $topic): void
    {
        if ($userId <= 0) {
            return;
        }
        $this->notifier->notifyUser($userId, $title, $message, ['in_app'], $topic, 'parent');
    }

    private function sendEmail(string $to, string $subject, string $html, string $fromKey): array
    {
        if ($to === '') {
            Log::warning('Payment event missing recipient email', ['subject' => $subject]);
            return ['ok' => false, 'message' => 'Missing recipient email.'];
        }

        $ok = $this->emailService->send($to, $subject, $html, $fromKey);
        if (!$ok) {
            Log::error('Payment event email failed', ['to' => $to, 'subject' => $subject]);
        }
        return ['ok' => $ok];
    }

    private function renderEmail(string $viewName, array $data, string $fallbackTitle): string
    {
        Log::debug('Skipping Blade email template', ['view' => $viewName]);

        return '<p>' . e($fallbackTitle) . '</p>';
    }
}
