<?php
declare(strict_types=1);

namespace App\Modules\HR\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Core\Logger;
use App\Modules\HR\Models\HrContract;
use App\Modules\Workflow\Services\WorkflowEngine;

/**
 * Contract Management Service
 *
 * Egyptian Labour Law (Art. 30-42):
 *   - Contract must be in Arabic, 3 copies
 *   - Max probation: 3 months
 *   - Notice period: 2 months (<10y), 3 months (>=10y)
 *   - Definite contracts: auto-renew if not terminated before end
 */
final class ContractService
{
    public static function create(array $data): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $profileId = (int) ($data['employee_profile_id'] ?? 0);
        if ($profileId <= 0) {
            return ['success' => false, 'error' => 'الموظف غير محدد'];
        }

        // Validate probation period
        $probationMonths = (int) ($data['probation_months'] ?? 0);
        if ($probationMonths > 3) {
            return ['success' => false, 'error' => 'فترة الاختبار لا يمكن أن تتجاوز 3 أشهر (مادة 33)'];
        }

        // Check for existing active contract
        $existingActive = HrContract::getActiveForEmployee($profileId);
        if ($existingActive) {
            return ['success' => false, 'error' => 'يوجد عقد ساري بالفعل — يجب إنهاؤه أو تجديده أولاً'];
        }

        // Generate contract number
        $contractNumber = self::generateContractNumber();

        $db->beginTransaction();
        try {
            $contractId = $db->insert('hr_contracts', [
                'employee_profile_id'    => $profileId,
                'contract_number'        => $contractNumber,
                'contract_type'          => $data['contract_type'] ?? 'definite',
                'start_date'             => $data['start_date'],
                'end_date'               => $data['end_date'] ?? null,
                'probation_months'       => $probationMonths,
                'working_hours_per_day'  => $data['working_hours_per_day'] ?? '8.00',
                'working_days_per_week'  => $data['working_days_per_week'] ?? 6,
                'notice_period_months'   => $data['notice_period_months'] ?? 2,
                'basic_salary'           => $data['basic_salary'] ?? '0.00',
                'total_package'          => $data['total_package'] ?? $data['basic_salary'] ?? '0.00',
                'terms_json'             => !empty($data['terms_ar']) ? json_encode($data['terms_ar'], JSON_UNESCAPED_UNICODE) : null,
                'renewal_of_contract_id' => $data['renewal_of_contract_id'] ?? null,
                'status'                 => 'draft',
                'notes'                  => $data['notes'] ?? null,
                '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,
            ]);

            $db->commit();

            if (WorkflowEngine::hasDefinition('hr_contract_approval')) {
                WorkflowEngine::createInstance('hr_contract_approval', 'hr_contracts', $contractId);
            }

            Logger::info("Contract created", ['contract_id' => $contractId, 'profile_id' => $profileId]);
            return ['success' => true, 'contract_id' => $contractId, 'contract_number' => $contractNumber];

        } catch (\Throwable $e) {
            $db->rollBack();
            Logger::error("Contract creation failed: " . $e->getMessage());
            return ['success' => false, 'error' => 'فشل إنشاء العقد: ' . $e->getMessage()];
        }
    }

    public static function renew(int $contractId, array $data): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $contract = $db->selectOne("SELECT * FROM hr_contracts WHERE id = ? AND is_archived = 0", [$contractId]);
        if (!$contract || $contract['status'] !== 'active') {
            return ['success' => false, 'error' => 'العقد غير موجود أو غير ساري'];
        }

        $db->beginTransaction();
        try {
            // Mark current contract as renewed
            $db->update('hr_contracts', [
                'status'     => 'renewed',
                'updated_at' => date('Y-m-d H:i:s'),
                'updated_by' => $employee ? (int) $employee->id : null,
            ], '`id` = ?', [$contractId]);

            // Create new contract
            $newContractNumber = self::generateContractNumber();
            $newContractId = $db->insert('hr_contracts', [
                'employee_profile_id'    => (int) $contract['employee_profile_id'],
                'contract_number'        => $newContractNumber,
                'contract_type'          => $data['contract_type'] ?? $contract['contract_type'],
                'start_date'             => $data['start_date'],
                'end_date'               => $data['end_date'] ?? null,
                'probation_months'       => 0,
                'working_hours_per_day'  => $data['working_hours_per_day'] ?? $contract['working_hours_per_day'],
                'working_days_per_week'  => $data['working_days_per_week'] ?? $contract['working_days_per_week'],
                'notice_period_months'   => $data['notice_period_months'] ?? $contract['notice_period_months'],
                'basic_salary'           => $data['basic_salary'] ?? $contract['basic_salary'],
                'total_package'          => $data['total_package'] ?? $contract['total_package'],
                'renewal_of_contract_id' => $contractId,
                'status'                 => 'active',
                'notes'                  => $data['notes'] ?? null,
                '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,
            ]);

            $db->commit();

            try {
                WorkflowEngine::transitionByEntity('hr_contracts', $contractId, 'renew');
            } catch (\Throwable $e) {
                Logger::warning("Workflow transition failed for contract renew", ['contract_id' => $contractId, 'error' => $e->getMessage()]);
            }

            EventBus::dispatch('hr.contract.renewed', [
                'old_contract_id' => $contractId,
                'new_contract_id' => $newContractId,
                'employee_profile_id' => (int) $contract['employee_profile_id'],
            ]);

            return ['success' => true, 'contract_id' => $newContractId, 'contract_number' => $newContractNumber];

        } catch (\Throwable $e) {
            $db->rollBack();
            return ['success' => false, 'error' => 'فشل تجديد العقد: ' . $e->getMessage()];
        }
    }

    public static function terminate(int $contractId, string $reason = ''): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $contract = $db->selectOne("SELECT * FROM hr_contracts WHERE id = ? AND is_archived = 0", [$contractId]);
        if (!$contract || $contract['status'] !== 'active') {
            return ['success' => false, 'error' => 'العقد غير موجود أو غير ساري'];
        }

        $db->update('hr_contracts', [
            'status'     => 'terminated',
            'notes'      => $reason ? ($contract['notes'] ? $contract['notes'] . "\n" . $reason : $reason) : $contract['notes'],
            'updated_at' => date('Y-m-d H:i:s'),
            'updated_by' => $employee ? (int) $employee->id : null,
        ], '`id` = ?', [$contractId]);

        try {
            WorkflowEngine::transitionByEntity('hr_contracts', $contractId, 'terminate');
        } catch (\Throwable $e) {
            Logger::warning("Workflow transition failed for contract terminate", ['contract_id' => $contractId, 'error' => $e->getMessage()]);
        }

        EventBus::dispatch('hr.contract.terminated', [
            'contract_id'        => $contractId,
            'employee_profile_id'=> (int) $contract['employee_profile_id'],
        ]);

        return ['success' => true];
    }

    public static function generateContractNumber(): string
    {
        $db = App::getInstance()->db();
        $year = date('Y');
        $prefix = 'CTR-' . $year . '-';
        $last = $db->selectOne(
            "SELECT contract_number FROM hr_contracts WHERE contract_number LIKE ? ORDER BY id DESC LIMIT 1",
            [$prefix . '%']
        );
        if ($last) {
            $parts = explode('-', $last['contract_number']);
            $seq = (int) end($parts) + 1;
        } else {
            $seq = 1;
        }
        return $prefix . str_pad((string) $seq, 5, '0', STR_PAD_LEFT);
    }
}
