<?php
declare(strict_types=1);

namespace App\Modules\Accounting\Services;

use App\Core\App;
use App\Core\EventBus;

final class CheckLifecycleService
{
    private static array $validTransitions = [
        'in_hand' => ['under_collection', 'endorsed', 'cancelled', 'returned'],
        'under_collection' => ['collected', 'bounced', 'returned'],
        'collected' => [],
        'bounced' => ['in_hand', 'under_collection', 'cancelled'],
        'endorsed' => ['returned'],
        'cancelled' => [],
        'paid' => [],
        'returned' => ['in_hand'],
    ];

    public static function canTransition(string $fromStatus, string $toStatus): bool
    {
        $allowed = self::$validTransitions[$fromStatus] ?? [];
        return in_array($toStatus, $allowed, true);
    }

    public static function transition(int $instrumentId, string $toStatus, array $options = []): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $instrument = $db->selectOne(
            "SELECT * FROM negotiable_instruments WHERE id = ?",
            [$instrumentId]
        );

        if (!$instrument) {
            return ['success' => false, 'error' => 'الورقة غير موجودة'];
        }

        $fromStatus = (string) $instrument['status'];

        if (!self::canTransition($fromStatus, $toStatus)) {
            return ['success' => false, 'error' => 'لا يمكن تغيير الحالة من "' . $fromStatus . '" إلى "' . $toStatus . '"'];
        }

        $db->beginTransaction();
        try {
            $updateData = ['status' => $toStatus];

            switch ($toStatus) {
                case 'under_collection':
                    $updateData['deposited_date'] = $options['date'] ?? date('Y-m-d');
                    if (!empty($options['bank_account_id'])) {
                        $updateData['bank_account_id'] = (int) $options['bank_account_id'];
                    }
                    break;

                case 'collected':
                    $updateData['collected_date'] = $options['date'] ?? date('Y-m-d');
                    break;

                case 'bounced':
                    $updateData['bounced_date'] = $options['date'] ?? date('Y-m-d');
                    $updateData['bounce_reason'] = $options['bounce_reason'] ?? null;
                    break;

                case 'endorsed':
                    $updateData['endorsed_to'] = $options['endorsed_to'] ?? null;
                    $updateData['endorsed_date'] = $options['date'] ?? date('Y-m-d');
                    break;
            }

            $db->update('negotiable_instruments', $updateData, 'id = ?', [$instrumentId]);

            $db->insert('instrument_status_history', [
                'instrument_id' => $instrumentId,
                'from_status' => $fromStatus,
                'to_status' => $toStatus,
                'transition_date' => $options['date'] ?? date('Y-m-d'),
                'bank_account_id' => $options['bank_account_id'] ?? null,
                'endorsed_to' => $options['endorsed_to'] ?? null,
                'bounce_reason' => $options['bounce_reason'] ?? null,
                'notes' => $options['notes'] ?? null,
                'created_by' => $employee ? (int) $employee->id : null,
            ]);

            EventBus::dispatch('instrument.status_changed', [
                'instrument_id' => $instrumentId,
                'from_status' => $fromStatus,
                'to_status' => $toStatus,
                'instrument' => $instrument,
            ]);

            $db->commit();
            return ['success' => true, 'instrument_id' => $instrumentId];
        } catch (\Throwable $e) {
            $db->rollBack();
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    public static function batchTransition(array $instrumentIds, string $toStatus, array $options = []): array
    {
        $results = ['success' => 0, 'failed' => 0, 'errors' => []];

        foreach ($instrumentIds as $id) {
            $result = self::transition((int) $id, $toStatus, $options);
            if ($result['success']) {
                $results['success']++;
            } else {
                $results['failed']++;
                $results['errors'][] = "#{$id}: " . $result['error'];
            }
        }

        return $results;
    }

    public static function getStatusHistory(int $instrumentId): array
    {
        $db = App::getInstance()->db();

        return $db->select(
            "SELECT h.*, e.full_name_ar as created_by_name
             FROM instrument_status_history h
             LEFT JOIN employees e ON e.id = h.created_by
             WHERE h.instrument_id = ?
             ORDER BY h.created_at DESC",
            [$instrumentId]
        );
    }

    public static function endorse(int $instrumentId, string $endorsedTo, ?string $date = null, ?string $notes = null): array
    {
        return self::transition($instrumentId, 'endorsed', [
            'endorsed_to' => $endorsedTo,
            'date' => $date ?? date('Y-m-d'),
            'notes' => $notes,
        ]);
    }

    public static function deposit(int $instrumentId, int $bankAccountId, ?string $date = null): array
    {
        return self::transition($instrumentId, 'under_collection', [
            'bank_account_id' => $bankAccountId,
            'date' => $date ?? date('Y-m-d'),
        ]);
    }

    public static function collect(int $instrumentId, ?string $date = null): array
    {
        return self::transition($instrumentId, 'collected', [
            'date' => $date ?? date('Y-m-d'),
        ]);
    }

    public static function bounce(int $instrumentId, string $reason, ?string $date = null): array
    {
        return self::transition($instrumentId, 'bounced', [
            'bounce_reason' => $reason,
            'date' => $date ?? date('Y-m-d'),
        ]);
    }
}
