<?php
declare(strict_types=1);

namespace App\Modules\Transfers\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Core\Logger;
use App\Modules\Archive\Services\ArchiveService;
use App\Modules\Members\Services\MemberNumberGenerator;
use App\Modules\Members\Services\NationalIdParser;
use App\Modules\Transfers\Models\TransferRequest;

final class TransferProcessor
{
    /**
     * Execute a complete transfer/separation.
     * 1. Take archive snapshot
     * 2. Archive source member FIRST (releases membership_number)
     * 3. Create new member record with SAME number
     * 4. Record number chain
     * 5. Transfer dependents / mark separated
     * 6. Mark transfer complete
     */
    public static function execute(int $transferRequestId): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $request = $db->selectOne("SELECT * FROM transfer_requests WHERE id = ?", [$transferRequestId]);
        if (!$request) {
            return ['success' => false, 'error' => 'طلب التحويل غير موجود'];
        }

        if ($request['status'] !== 'approved' && $request['status'] !== 'fee_paid') {
            return ['success' => false, 'error' => 'طلب التحويل غير مُعتمد أو لم يتم السداد'];
        }

        $sourceMember = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $request['source_member_id']]);
        if (!$sourceMember) {
            return ['success' => false, 'error' => 'العضو المصدر غير موجود'];
        }

        $db->beginTransaction();
        try {
            // 1. Take archive snapshot of source member
            $snapshotId = ArchiveService::takeSnapshot(
                'members',
                (int) $sourceMember['id'],
                $request['transfer_type'],
                'لقطة أرشيفية قبل التحويل/الفصل — طلب #' . $transferRequestId,
                null,
                $sourceMember['membership_number']
            );

            // 2. Determine the subject of transfer
            $subjectName = $sourceMember['full_name_ar'];
            $subjectData = $sourceMember;
            $isFullTransfer = !$request['child_id'] && !$request['spouse_id'];

            if ($request['child_id']) {
                $child = $db->selectOne("SELECT * FROM children WHERE id = ?", [(int) $request['child_id']]);
                if ($child) {
                    $subjectName = $child['full_name_ar'];
                    $subjectData = $child;
                }
            } elseif ($request['spouse_id']) {
                $spouse = $db->selectOne("SELECT * FROM spouses WHERE id = ?", [(int) $request['spouse_id']]);
                if ($spouse) {
                    $subjectName = $spouse['full_name_ar'];
                    $subjectData = $spouse;
                }
            }

            // For full_transfer type, use recipient data stored in notes
            $recipientData = [];
            if ($request['transfer_type'] === 'full_transfer' && !empty($request['notes'])) {
                $notesDecoded = json_decode($request['notes'], true);
                $recipientData = $notesDecoded['recipient_data'] ?? [];
            }

            $sameNumber = $sourceMember['membership_number'];

            // Find the separation_fee payment that was made for this transfer
            $transferPayment = $db->selectOne(
                "SELECT id FROM payments WHERE member_id = ? AND payment_type = 'separation_fee' AND related_entity_type = 'transfer_requests' AND related_entity_id = ? AND is_voided = 0 ORDER BY id DESC LIMIT 1",
                [(int) $request['source_member_id'], $transferRequestId]
            );
            $transferPaymentId = $transferPayment ? (int) $transferPayment['id'] : null;

            // 3. Archive source member FIRST — releases the unique membership_number
            $db->update('members', [
                'membership_number' => null,
                'status'            => 'transferred',
                'is_archived'       => 1,
                'archived_at'       => date('Y-m-d H:i:s'),
                'updated_at'        => date('Y-m-d H:i:s'),
            ], '`id` = ?', [(int) $sourceMember['id']]);

            // Verify number is actually released (no other member holds it)
            $numberConflict = $db->selectOne(
                "SELECT id FROM members WHERE membership_number = ? AND id != ?",
                [$sameNumber, (int) $sourceMember['id']]
            );
            if ($numberConflict) {
                $sameNumber = MemberNumberGenerator::generateNext();
            }

            // 4. Create new member record with SAME membership number
            // Derive date_of_birth and gender from national_id if not directly available
            $dob = $recipientData['date_of_birth'] ?? $subjectData['date_of_birth'] ?? null;
            $gender = $recipientData['gender'] ?? $subjectData['gender'] ?? null;
            $nid = $recipientData['national_id'] ?? $subjectData['national_id'] ?? null;
            if ((!$dob || !$gender) && $nid && strlen($nid) === 14) {
                $parsed = NationalIdParser::parse($nid);
                if ($parsed['is_valid']) {
                    $dob = $dob ?: $parsed['dob'];
                    $gender = $gender ?: $parsed['gender'];
                }
            }

            $newMemberData = [
                'full_name_ar'           => $recipientData['full_name_ar'] ?? $subjectData['full_name_ar'] ?? $subjectName,
                'full_name_en'           => $recipientData['full_name_en'] ?? $subjectData['full_name_en'] ?? null,
                'national_id'            => $nid,
                'passport_number'        => $subjectData['passport_number'] ?? null,
                'id_type'                => $subjectData['id_type'] ?? 'national_id',
                'date_of_birth'          => $dob ?? '1900-01-01',
                'gender'                 => $gender ?? 'male',
                'nationality'            => $recipientData['nationality'] ?? $subjectData['nationality'] ?? 'مصري',
                'branch_id'              => (int) $sourceMember['branch_id'],
                'membership_type'        => 'working',
                'member_category'        => 'working_member',
                'status'                 => 'active',
                'activated_at'           => date('Y-m-d H:i:s'),
                'activated_by_payment_id'=> $transferPaymentId,
                'qualification_id'       => $recipientData['qualification_id'] ?? $subjectData['qualification_id'] ?? $sourceMember['qualification_id'],
                'phone_mobile'           => $recipientData['phone_mobile'] ?? $subjectData['mobile'] ?? $subjectData['phone_mobile'] ?? $sourceMember['phone_mobile'],
                'membership_value'       => $request['new_membership_value'],
                'membership_number'      => $sameNumber,
                'created_at'             => date('Y-m-d H:i:s'),
                'updated_at'             => date('Y-m-d H:i:s'),
                'created_by'             => $employee ? (int) $employee->id : null,
            ];

            // Add optional recipient fields for full_transfer
            $optionalFields = ['marital_status', 'religion', 'phone_home', 'email', 'emergency_name', 'emergency_phone', 'residence_address', 'area', 'governorate', 'occupation', 'job_title'];
            foreach ($optionalFields as $field) {
                if (!empty($recipientData[$field])) {
                    $newMemberData[$field] = $recipientData[$field];
                }
            }

            $newMemberId = $db->insert('members', $newMemberData);

            // 5. Record number chain
            ArchiveService::recordNumberTransfer(
                $sameNumber,
                $request['transfer_type'],
                'members',
                $newMemberId,
                null
            );

            // 6. Update source dependents
            if ($request['child_id']) {
                $db->update('children', [
                    'status'        => 'separated',
                    'classification'=> 'separated',
                    'updated_at'    => date('Y-m-d H:i:s'),
                ], '`id` = ?', [(int) $request['child_id']]);
            } elseif ($request['spouse_id']) {
                $db->update('spouses', [
                    'status'     => 'separated',
                    'updated_at' => date('Y-m-d H:i:s'),
                ], '`id` = ?', [(int) $request['spouse_id']]);
            }

            // Child separation: create dependents specified on the form
            if ($request['transfer_type'] === 'child_separation' && !empty($request['notes'])) {
                $notesDecoded = json_decode($request['notes'], true) ?: [];
                $depsData = $notesDecoded['dependents_data'] ?? [];

                if (!empty($depsData['spouses'])) {
                    foreach ($depsData['spouses'] as $sp) {
                        if (empty($sp['full_name_ar'])) continue;
                        $spNid = $sp['national_id'] ?? null;
                        $spDob = null;
                        if ($spNid && strlen($spNid) === 14) {
                            $spParsed = NationalIdParser::parse($spNid);
                            if ($spParsed['is_valid']) $spDob = $spParsed['dob'];
                        }
                        $spouseRow = [
                            'member_id'    => $newMemberId,
                            'full_name_ar' => $sp['full_name_ar'],
                            'national_id'  => $spNid,
                            'status'       => 'active',
                            'is_archived'  => 0,
                            'created_at'   => date('Y-m-d H:i:s'),
                            'updated_at'   => date('Y-m-d H:i:s'),
                        ];
                        if ($spDob) $spouseRow['date_of_birth'] = $spDob;
                        $db->insert('spouses', $spouseRow);
                    }
                }

                if (!empty($depsData['children'])) {
                    foreach ($depsData['children'] as $ch) {
                        if (empty($ch['full_name_ar'])) continue;
                        $chNid = $ch['national_id'] ?? null;
                        $chDob = $ch['date_of_birth'] ?? null;
                        $chGender = $ch['gender'] ?? 'male';
                        if (!$chDob && $chNid && strlen($chNid) === 14) {
                            $chParsed = NationalIdParser::parse($chNid);
                            if ($chParsed['is_valid']) {
                                $chDob = $chParsed['dob'];
                                $chGender = $chParsed['gender'] ?? $chGender;
                            }
                        }
                        $db->insert('children', [
                            'member_id'      => $newMemberId,
                            'full_name_ar'   => $ch['full_name_ar'],
                            'national_id'    => $chNid,
                            'date_of_birth'  => $chDob ?? '1900-01-01',
                            'gender'         => $chGender,
                            'classification' => 'active',
                            'status'         => 'active',
                            'is_archived'    => 0,
                            'created_at'     => date('Y-m-d H:i:s'),
                            'updated_at'     => date('Y-m-d H:i:s'),
                        ]);
                    }
                }

                $tempsArr = $depsData['temps'] ?? $depsData['temporary_members'] ?? [];
                if (!empty($tempsArr)) {
                    foreach ($tempsArr as $tm) {
                        if (empty($tm['full_name_ar'])) continue;
                        $db->insert('temporary_members', [
                            'member_id'    => $newMemberId,
                            'full_name_ar' => $tm['full_name_ar'],
                            'national_id'  => $tm['national_id'] ?? null,
                            'status'       => 'active',
                            'is_archived'  => 0,
                            'created_at'   => date('Y-m-d H:i:s'),
                            'updated_at'   => date('Y-m-d H:i:s'),
                        ]);
                    }
                }
            }

            // Full membership transfer: move all dependents to new member
            if ($isFullTransfer) {
                $db->query("UPDATE spouses SET member_id = ?, updated_at = NOW() WHERE member_id = ? AND is_archived = 0", [$newMemberId, (int) $sourceMember['id']]);
                $db->query("UPDATE children SET member_id = ?, updated_at = NOW() WHERE member_id = ? AND is_archived = 0", [$newMemberId, (int) $sourceMember['id']]);
                $db->query("UPDATE temporary_members SET member_id = ?, updated_at = NOW() WHERE member_id = ? AND is_archived = 0", [$newMemberId, (int) $sourceMember['id']]);
            }

            // 7. Mark transfer request complete
            $db->update('transfer_requests', [
                'target_member_id'     => $newMemberId,
                'new_membership_number'=> $sameNumber,
                'archive_snapshot_id'  => $snapshotId,
                'completed_at'         => date('Y-m-d H:i:s'),
                'status'               => 'completed',
                'updated_at'           => date('Y-m-d H:i:s'),
                'updated_by'           => $employee ? (int) $employee->id : null,
            ], '`id` = ?', [$transferRequestId]);

            $db->commit();

            EventBus::dispatch('transfer.completed', [
                'transfer_id'      => $transferRequestId,
                'source_member_id' => (int) $request['source_member_id'],
                'target_member_id' => $newMemberId,
                'new_number'       => $sameNumber,
                'transfer_type'    => $request['transfer_type'],
                'fee_amount'       => $request['total_fee'] ?? $request['separation_fee'] ?? '0.00',
                'old_number'       => $sourceMember['membership_number'] ?? null,
            ]);

            Logger::info("Transfer completed", [
                'transfer_id' => $transferRequestId,
                'new_member'  => $newMemberId,
                'new_number'  => $sameNumber,
            ]);

            return [
                'success'          => true,
                'new_member_id'    => $newMemberId,
                'new_number'       => $sameNumber,
                'snapshot_id'      => $snapshotId,
                'transfer_id'      => $transferRequestId,
            ];

        } catch (\Throwable $e) {
            $db->rollBack();
            Logger::error("Transfer failed: " . $e->getMessage(), ['transfer_id' => $transferRequestId]);
            return ['success' => false, 'error' => 'فشل في إتمام التحويل: ' . $e->getMessage()];
        }
    }
}