<?php

namespace App\Services\Import\Handlers;

use App\Models\ClientCase;
use App\Models\Contract;
use App\Models\Import;
use App\Services\Import\BaseEntityHandler;
use App\Services\Import\EntityResolutionService;
use Illuminate\Support\Facades\Log;

class ContractHandler extends BaseEntityHandler
{
    protected EntityResolutionService $resolutionService;

    public function __construct($entityConfig = null)
    {
        parent::__construct($entityConfig);
        $this->resolutionService = new EntityResolutionService();
    }

    public function getEntityClass(): string
    {
        return Contract::class;
    }

    public function resolve(array $mapped, array $context = []): mixed
    {
        $reference = $mapped['reference'] ?? null;

        if (! $reference) {
            return null;
        }

        $query = Contract::query();

        // Scope by client if available
        if ($clientId = $context['import']->client_id) {
            $query->join('client_cases', 'contracts.client_case_id', '=', 'client_cases.id')
                ->where('client_cases.client_id', $clientId)
                ->select('contracts.*');
        }

        return $query->where('contracts.reference', $reference)->first();
    }

    public function process(Import $import, array $mapped, array $raw, array $context = []): array
    {
        // Check for existing contract (using resolve method which handles client scoping)
        $existing = $this->resolve($mapped, $context);

        if ($existing) {
            

            // Check for reactivation FIRST (before update_mode check)
            $reactivate = $this->shouldReactivate($context);

            Log::info('ContractHandler: Found existing Contract', [
                'contract_id' => $existing->id,
                'reference' => $mapped['reference'] ?? null,
                'context' => $context['import']
            ]);

            if ($reactivate && $this->needsReactivation($existing)) {
                $reactivated = $this->attemptReactivation($existing, $context);
                Log::info('ContractHandler: Reactivate', ['reactivated' => $reactivated]);
                if ($reactivated) {
                    return [
                        'action' => 'reactivated',
                        'entity' => $existing,
                        'message' => 'Contract reactivated',
                    ];
                }
            }

            // Check update mode
            $mode = $this->getOption('update_mode', 'update');
            if ($mode === 'skip') {
                return [
                    'action' => 'skipped',
                    'entity' => $existing,
                    'message' => 'Contract already exists (skip mode)',
                ];
            }

            // Update existing contract
            $payload = $this->buildPayload($mapped, $existing);
            $payload = $this->mergeJsonFields($payload, $existing);
            $appliedFields = $this->trackAppliedFields($existing, $payload);

            if (empty($appliedFields)) {
                return [
                    'action' => 'skipped',
                    'entity' => $existing,
                    'message' => 'No changes detected',
                ];
            }

            $existing->fill($payload);
            $existing->save();

            return [
                'action' => 'updated',
                'entity' => $existing,
                'applied_fields' => $appliedFields,
            ];
        }

        // Create new contract
        $contract = new Contract;
        $payload = $this->buildPayload($mapped, $contract);
        
        // Get client_case_id from context or mapped data
        $clientCaseId = $mapped['client_case_id'] 
            ?? $context['client_case']?->entity?->id 
            ?? null;
        
        // If no client_case_id, try to create/find one automatically (using EntityResolutionService)
        if (!$clientCaseId) {
            // Add mapped data to context for EntityResolutionService
            $context['mapped'] = $mapped;
            $clientCaseId = $this->findOrCreateClientCaseId($context);
        }
        
        if (!$clientCaseId) {
            return [
                'action' => 'invalid',
                'message' => 'Contract requires client_case_id (import must have client_id)',
            ];
        }
        
        $payload['client_case_id'] = $clientCaseId;
        
        // Ensure required defaults
        if (!isset($payload['type_id'])) {
            $payload['type_id'] = $this->getDefaultContractTypeId();
        }
        if (!isset($payload['start_date'])) {
            $payload['start_date'] = now()->toDateString();
        }
        
        $contract->fill($payload);
        $contract->save();

        return [
            'action' => 'inserted',
            'entity' => $contract,
            'applied_fields' => array_keys($payload),
        ];
    }

    protected function buildPayload(array $mapped, $model): array
    {
        $payload = [];

        // Map fields according to contract schema
        $fieldMap = [
            'reference' => 'reference',
            'description' => 'description',
            'amount' => 'amount',
            'currency' => 'currency',
            'start_date' => 'start_date',
            'end_date' => 'end_date',
            'active' => 'active',
            'type_id' => 'type_id',
            'client_case_id' => 'client_case_id',
        ];

        foreach ($fieldMap as $source => $target) {
            if (array_key_exists($source, $mapped)) {
                $payload[$target] = $mapped[$source];
            }
        }

        // Handle meta field - merge grouped meta into flat structure
        if (!empty($mapped['meta']) && is_array($mapped['meta'])) {
            $metaData = [];
            foreach ($mapped['meta'] as $grp => $entries) {
                if (!is_array($entries)) {
                    continue;
                }
                foreach ($entries as $k => $v) {
                    $metaData[$k] = $v;
                }
            }
            if (!empty($metaData)) {
                $payload['meta'] = $metaData;
            }
        }

        return $payload;
    }
    
    private function getDefaultContractTypeId(): int
    {
        return (int) (\App\Models\ContractType::min('id') ?? 1);
    }

    /**
     * Check if reactivation should be attempted.
     */
    protected function shouldReactivate(array $context): bool
    {
        // Row-level reactivate column takes precedence
        if (isset($context['raw']['reactivate'])) {
            return filter_var($context['raw']['reactivate'], FILTER_VALIDATE_BOOLEAN);
        }

        // Then import-level
        if (isset($context['import']->reactivate)) {
            return (bool) $context['import']->reactivate;
        }

        // Finally template-level
        if (isset($context['import']->template?->reactivate)) {
            return (bool) $context['import']->template->reactivate;
        }

        return false;
    }

    /**
     * Check if entity needs reactivation.
     */
    protected function needsReactivation($entity): bool
    {
        return $entity->active == 0 || $entity->deleted_at !== null;
    }

    /**
     * Attempt to reactivate soft-deleted or inactive contract.
     */
    protected function attemptReactivation(Contract $contract, array $context): bool
    {
        if (! $this->getOption('supports_reactivation', false)) {
            return false;
        }

        try {
            if ($contract->trashed()) {
                $contract->restore();
            }

            $contract->active = 1;

            $contract->save();

            return true;
        } catch (\Throwable $e) {
            \Log::error('Contract reactivation failed', [
                'contract_id' => $contract->id,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    /**
     * Merge JSON fields instead of overwriting.
     */
    protected function mergeJsonFields(array $payload, $existing): array
    {
        $mergeFields = $this->getOption('merge_json_fields', []);

        foreach ($mergeFields as $field) {
            if (isset($payload[$field]) && isset($existing->{$field})) {
                $existingData = is_array($existing->{$field}) ? $existing->{$field} : [];
                $newData = is_array($payload[$field]) ? $payload[$field] : [];
                $payload[$field] = array_merge($existingData, $newData);
            }
        }

        return $payload;
    }
    
    /**
     * Find or create a ClientCase for this contract (using EntityResolutionService).
     */
    protected function findOrCreateClientCaseId(array $context): ?int
    {
        $import = $context['import'] ?? null;
        $mapped = $context['mapped'] ?? [];
        $clientId = $import?->client_id ?? null;
        
        if (!$clientId) {
            return null;
        }
        
        // PHASE 4: Use EntityResolutionService to resolve or create ClientCase
        // This will reuse existing ClientCase when possible
        $clientCaseId = $this->resolutionService->resolveOrCreateClientCaseForContract(
            $import,
            $mapped,
            $context
        );
        
        if ($clientCaseId) {
            Log::info('ContractHandler: Resolved/Created ClientCase for Contract', [
                'client_case_id' => $clientCaseId,
            ]);
        }
        
        return $clientCaseId;
    }
    
    /**
     * Generate a unique client_ref.
     */
    protected function generateClientRef(int $clientId): string
    {
        $timestamp = now()->format('ymdHis');
        $random = substr(md5(uniqid()), 0, 4);
        return "C{$clientId}-{$timestamp}-{$random}";
    }
}