<?php
declare(strict_types=1);

namespace App\Modules\Installments\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Core\EventBus;
use App\Modules\Payments\Services\PaymentService;
use App\Modules\Installments\Services\InstallmentCalculator;

class InstallmentController extends Controller
{
    public function index(Request $request): Response
    {
        $db = App::getInstance()->db();
        $filters = [
            'search' => trim((string) $request->get('q', '')),
            'status' => $request->get('status', ''),
            'overdue_only' => $request->get('overdue_only', ''),
        ];
        $page = max(1, (int) $request->get('page', 1));
        $perPage = 25;
        $where = '1=1';
        $params = [];

        if (!empty($filters['status'])) { $where .= ' AND ip.status = ?'; $params[] = $filters['status']; }
        if (!empty($filters['search'])) {
            $where .= ' AND (m.full_name_ar LIKE ? OR m.membership_number LIKE ?)';
            $s = '%' . $filters['search'] . '%'; $params[] = $s; $params[] = $s;
        }

        $countRow = $db->selectOne("SELECT COUNT(*) as cnt FROM installment_plans ip JOIN members m ON m.id = ip.member_id WHERE {$where}", $params);
        $total = (int) ($countRow['cnt'] ?? 0);
        $offset = ($page - 1) * $perPage;

        $rows = $db->select(
            "SELECT ip.*, m.full_name_ar as member_name, m.membership_number,
                    (SELECT COALESCE(SUM(paid_amount), 0) FROM installment_schedule WHERE installment_plan_id = ip.id AND status = 'paid') as total_paid_installments,
                    (SELECT COUNT(*) FROM installment_schedule WHERE installment_plan_id = ip.id AND status = 'pending' AND due_date < CURDATE()) as overdue_count
             FROM installment_plans ip
             JOIN members m ON m.id = ip.member_id
             WHERE {$where}
             " . ($filters['overdue_only'] ? "HAVING overdue_count > 0" : "") . "
             ORDER BY ip.created_at DESC LIMIT {$perPage} OFFSET {$offset}",
            $params
        );

        $pagination = \App\Core\Pagination::paginate($total, $perPage, $page);

        return $this->view('Installments.Views.index', [
            'rows'       => $rows,
            'pagination' => $pagination,
            'filters'    => $filters,
        ]);
    }

    public function show(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $plan = $db->selectOne(
            "SELECT ip.*, m.full_name_ar as member_name, m.membership_number
             FROM installment_plans ip JOIN members m ON m.id = ip.member_id WHERE ip.id = ?",
            [(int) $id]
        );
        if (!$plan) return $this->redirect('/installments')->withError('الخطة غير موجودة');

        $schedule = $db->select(
            "SELECT * FROM installment_schedule WHERE installment_plan_id = ? ORDER BY installment_number ASC",
            [(int) $id]
        );

        return $this->view('Installments.Views.show', [
            'plan'     => $plan,
            'schedule' => $schedule,
        ]);
    }

    public function create(Request $request, string $memberId): Response
    {
        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ? AND is_archived = 0", [(int) $memberId]);
        if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');

        $existingActive = $db->selectOne("SELECT * FROM installment_plans WHERE member_id = ? AND status = 'active'", [(int) $memberId]);

        $rateData     = \App\Modules\Rules\Services\RuleEngine::get('INSTALLMENT_INTEREST_RATE');
        $maxMonthsData = \App\Modules\Rules\Services\RuleEngine::get('INSTALLMENT_MAX_MONTHS');

        return $this->view('Installments.Views.create', [
            'member'         => $member,
            'existingActive' => $existingActive,
            'interestRate'   => $rateData['percentage'] ?? '22.00',
            'maxMonths'      => $maxMonthsData['months'] ?? 30,
        ]);
    }

    public function store(Request $request, string $memberId): Response
    {
        $this->authorize('installment.create_plan');
        $db = App::getInstance()->db();

        $member = $db->selectOne("SELECT * FROM members WHERE id = ? AND is_archived = 0", [(int) $memberId]);
        if (!$member) {
            return $this->redirect('/members')->withError('العضو غير موجود');
        }

        $totalAmount = trim((string) $request->post('total_amount', '0'));
        $downPayment = trim((string) $request->post('down_payment', '0'));
        $months = (int) $request->post('number_of_months', 0);
        $startDate = trim((string) $request->post('start_date', date('Y-m-d')));
        $notes = trim((string) $request->post('notes', ''));

        $calc = InstallmentCalculator::calculate($totalAmount, $downPayment, $months, $startDate);
        if (!($calc['success'] ?? false)) {
            $session = App::getInstance()->session();
            $session->flash('_alerts', array_map(fn($e) => ['type' => 'error', 'message' => $e], $calc['errors'] ?? []));
            $session->flash('_old_input', $request->all());
            return $this->redirect("/installments/create/{$memberId}");
        }

        $employee = App::getInstance()->currentEmployee();

        $db->beginTransaction();
        try {
            $planId = $db->insert('installment_plans', [
                'member_id'           => (int) $memberId,
                'total_amount'        => $totalAmount,
                'down_payment'        => $downPayment,
                'remaining_balance'   => $calc['remaining_balance'],
                'interest_rate'       => $calc['interest_rate'],
                'total_interest'      => $calc['total_interest'],
                'total_with_interest' => $calc['total_with_interest'],
                'number_of_months'    => $months,
                'monthly_payment'     => $calc['monthly_payment'],
                'start_date'          => $startDate,
                'cash_settlement_date'=> $calc['cash_settlement_date'],
                'status'              => 'active',
                'notes'               => $notes ?: null,
                'created_by'          => $employee ? (int) $employee->id : null,
                'created_at'          => date('Y-m-d H:i:s'),
                'updated_at'          => date('Y-m-d H:i:s'),
            ]);

            foreach ($calc['schedule'] as $item) {
                $db->insert('installment_schedule', [
                    'installment_plan_id' => $planId,
                    'installment_number'  => $item['number'],
                    'due_date'            => $item['due_date'],
                    'amount'              => $item['amount'],
                    'principal'           => $item['principal'],
                    'interest'            => $item['interest'],
                    'status'              => 'pending',
                    'created_at'          => date('Y-m-d H:i:s'),
                ]);
            }

            $db->commit();
        } catch (\Throwable $e) {
            $db->rollBack();
            return $this->redirect("/installments/create/{$memberId}")->withError('خطأ: ' . $e->getMessage());
        }

        EventBus::dispatch('installment_plan.created', [
            'plan_id'   => $planId,
            'member_id' => (int) $memberId,
        ]);

        return $this->redirect("/installments/{$planId}")->withSuccess(
            "تم إنشاء خطة التقسيط — {$months} قسط بإجمالي " . money($calc['total_with_interest'])
        );
    }

    public function payInstallment(Request $request, string $planId, string $scheduleId): Response
    {
        $db = App::getInstance()->db();
        $plan = $db->selectOne("SELECT * FROM installment_plans WHERE id = ?", [(int) $planId]);
        if (!$plan) return $this->redirect('/installments')->withError('الخطة غير موجودة');

        $item = $db->selectOne("SELECT * FROM installment_schedule WHERE id = ? AND installment_plan_id = ?", [(int) $scheduleId, (int) $planId]);
        if (!$item || $item['status'] === 'paid') return $this->redirect("/installments/{$planId}")->withError('القسط غير موجود أو مدفوع');

        $amount = $item['amount'];
        $paymentMethod = trim((string) $request->post('payment_method', 'cash'));

        $result = PaymentService::processPayment([
            'member_id'           => (int) $plan['member_id'],
            'amount'              => $amount,
            'payment_type'        => 'installment',
            'payment_method'      => $paymentMethod,
            'related_entity_type' => 'installment_schedule',
            'related_entity_id'   => (int) $scheduleId,
            'description'         => 'قسط رقم ' . $item['installment_number'] . ' — خطة #' . $planId,
        ]);

        if (!$result['success']) return $this->redirect("/installments/{$planId}")->withError($result['error']);

        $db->update('installment_schedule', [
            'paid_amount' => $amount,
            'payment_id'  => $result['payment_id'],
            'status'      => 'paid',
            'paid_at'     => date('Y-m-d H:i:s'),
            'updated_at'  => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $scheduleId]);

        // Check if all paid → complete plan
        $remaining = $db->selectOne("SELECT COUNT(*) as cnt FROM installment_schedule WHERE installment_plan_id = ? AND status = 'pending'", [(int) $planId]);
        if ((int) ($remaining['cnt'] ?? 0) === 0) {
            $db->update('installment_plans', ['status' => 'completed', 'updated_at' => date('Y-m-d H:i:s')], '`id` = ?', [(int) $planId]);
        }

        EventBus::dispatch('installment.paid', ['plan_id' => (int) $planId, 'schedule_id' => (int) $scheduleId, 'member_id' => (int) $plan['member_id']]);

        return $this->redirect("/installments/{$planId}")->withSuccess('تم دفع القسط — إيصال: ' . $result['receipt_number']);
    }
}