<?php
declare(strict_types=1);

namespace App\Modules\Payments\Models;

use App\Core\Model;
use App\Core\App;
use App\Core\Pagination;

class Payment extends Model
{
    protected static string $table = 'payments';
    protected static string $primaryKey = 'id';
    protected static bool $timestamps = true;
    protected static bool $softDelete = false;
    protected static bool $dispatchEvents = true;

    protected static array $fillable = [
        'member_id', 'receipt_id', 'payment_type', 'amount', 'currency',
        'payment_method', 'check_number', 'check_bank', 'check_date', 'check_status',
        'visa_reference', 'transfer_reference', 'transfer_bank',
        'related_entity_type', 'related_entity_id', 'notes',
        'payment_date', 'received_by_employee_id',
        'is_voided', 'voided_at', 'voided_by', 'void_reason',
    ];

    public static function getForMember(int $memberId, bool $includeVoided = false): array
    {
        $db = App::getInstance()->db();
        $where = $includeVoided ? '' : ' AND p.is_voided = 0';
        return $db->select(
            "SELECT p.*, r.receipt_number, e.full_name_ar as received_by_name
             FROM payments p
             LEFT JOIN receipts r ON r.id = p.receipt_id
             LEFT JOIN employees e ON e.id = p.received_by_employee_id
             WHERE p.member_id = ?{$where}
             ORDER BY p.payment_date DESC, p.id DESC",
            [$memberId]
        );
    }

    public static function getTotalPaidForMember(int $memberId): string
    {
        $db = App::getInstance()->db();
        $row = $db->selectOne(
            "SELECT COALESCE(SUM(amount), 0) as total FROM payments WHERE member_id = ? AND is_voided = 0",
            [$memberId]
        );
        return $row['total'] ?? '0.00';
    }

    public static function search(array $filters, int $perPage = 25, int $page = 1): array
    {
        $db = App::getInstance()->db();
        $where = '1=1';
        $params = [];

        if (!empty($filters['member_id'])) {
            $where .= ' AND p.member_id = ?';
            $params[] = (int) $filters['member_id'];
        }
        if (!empty($filters['payment_type'])) {
            $where .= ' AND p.payment_type = ?';
            $params[] = $filters['payment_type'];
        }
        if (!empty($filters['payment_method'])) {
            $where .= ' AND p.payment_method = ?';
            $params[] = $filters['payment_method'];
        }
        if (!empty($filters['date_from'])) {
            $where .= ' AND p.payment_date >= ?';
            $params[] = $filters['date_from'];
        }
        if (!empty($filters['date_to'])) {
            $where .= ' AND p.payment_date <= ?';
            $params[] = $filters['date_to'];
        }
        if (isset($filters['is_voided']) && $filters['is_voided'] !== '') {
            $where .= ' AND p.is_voided = ?';
            $params[] = (int) $filters['is_voided'];
        } else {
            $where .= ' AND p.is_voided = 0';
        }
        if (!empty($filters['search'])) {
            $where .= ' AND (m.full_name_ar LIKE ? OR m.membership_number LIKE ? OR r.receipt_number LIKE ?)';
            $s = '%' . $filters['search'] . '%';
            $params[] = $s;
            $params[] = $s;
            $params[] = $s;
        }

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

        $rows = $db->select(
            "SELECT p.*, m.full_name_ar as member_name, m.membership_number, r.receipt_number, e.full_name_ar as received_by_name
             FROM payments p
             JOIN members m ON m.id = p.member_id
             LEFT JOIN receipts r ON r.id = p.receipt_id
             LEFT JOIN employees e ON e.id = p.received_by_employee_id
             WHERE {$where}
             ORDER BY p.payment_date DESC, p.id DESC
             LIMIT {$perPage} OFFSET {$offset}",
            $params
        );

        return ['data' => $rows, 'pagination' => Pagination::paginate($total, $perPage, $page)];
    }

    public static function getDailyTotals(string $date, ?int $branchId = null): array
    {
        $db = App::getInstance()->db();
        $where = 'p.payment_date = ? AND p.is_voided = 0';
        $params = [$date];
        if ($branchId) {
            $where .= ' AND m.branch_id = ?';
            $params[] = $branchId;
        }

        $byType = $db->select(
            "SELECT p.payment_type, COUNT(*) as count, SUM(p.amount) as total
             FROM payments p JOIN members m ON m.id = p.member_id
             WHERE {$where} GROUP BY p.payment_type ORDER BY total DESC",
            $params
        );

        $byMethod = $db->select(
            "SELECT p.payment_method, COUNT(*) as count, SUM(p.amount) as total
             FROM payments p JOIN members m ON m.id = p.member_id
             WHERE {$where} GROUP BY p.payment_method ORDER BY total DESC",
            $params
        );

        $grandTotal = $db->selectOne(
            "SELECT COUNT(*) as count, COALESCE(SUM(p.amount), 0) as total
             FROM payments p JOIN members m ON m.id = p.member_id
             WHERE {$where}",
            $params
        );

        return [
            'by_type'     => $byType,
            'by_method'   => $byMethod,
            'grand_total' => $grandTotal,
        ];
    }

    public static function getPaymentTypeLabel(string $type): string
    {
        return match ($type) {
            'membership_fee'        => 'رسوم عضوية',
            'form_fee'              => 'رسوم استمارة',
            'addition_fee'          => 'رسوم إضافة',
            'annual_subscription'   => 'اشتراك سنوي',
            'fine'                  => 'غرامة',
            'penalty'               => 'عقوبة مالية',
            'installment'           => 'قسط',
            'down_payment'          => 'مقدم',
            'development_fee'       => 'رسوم تنمية',
            'carnet_replacement'    => 'بدل فاقد كارنيه',
            'separation_fee'        => 'رسوم فصل',
            'transfer_fee'          => 'رسوم تحويل',
            'death_fee'             => 'رسوم وفاة',
            'waiver_fee'            => 'رسوم تنازل',
            'divorce_fee'           => 'رسوم طلاق',
            'sports_subscription'   => 'اشتراك نشاط رياضي',
            'seasonal_fee'          => 'رسوم عضوية موسمية',
            'companion_surcharge'   => 'رسوم ملحقين إضافيين',
            'reinstatement_fee'     => 'رسوم إعادة العضوية',
            'hourly_booking'        => 'حجز بالساعة',
            'early_settlement'      => 'تسوية مبكرة',
            'booking_fee'           => 'رسوم حجز',
            'sale'                  => 'مبيعات',
            'other'                 => 'أخرى',
            default                 => $type,
        };
    }

    public static function getPaymentMethodLabel(string $method): string
    {
        return match ($method) {
            'cash'          => 'نقدي',
            'check'         => 'شيك',
            'visa'          => 'فيزا / بطاقة',
            'bank_transfer' => 'تحويل بنكي',
            default         => $method,
        };
    }
}