<?php

namespace App\Services\Import\Handlers;

use App\Models\Account;
use App\Models\Import;
use App\Services\Import\BaseEntityHandler;
use App\Services\Import\DecimalNormalizer;

class AccountHandler extends BaseEntityHandler
{
    public function getEntityClass(): string
    {
        return Account::class;
    }

    /**
     * Override validate to handle contract_id and reference from context.
     * Both contract_id and reference are populated in process() (reference defaults to contract reference).
     */
    public function validate(array $mapped): array
    {
        // Remove contract_id and reference from validation - both will be populated in process()
        // Reference defaults to contract.reference if not set (matching v1 behavior)
        $rules = $this->entityConfig?->validation_rules ?? [];
        
        unset($rules['contract_id'], $rules['reference']);

        if (empty($rules)) {
            return ['valid' => true, 'errors' => []];
        }

        $validator = \Illuminate\Support\Facades\Validator::make($mapped, $rules);

        if ($validator->fails()) {
            return [
                'valid' => false,
                'errors' => $validator->errors()->all(),
            ];
        }

        return ['valid' => true, 'errors' => []];
    }

    public function resolve(array $mapped, array $context = []): mixed
    {
        $reference = $mapped['reference'] ?? null;
        $contractId = $mapped['contract_id'] ?? $context['contract']['entity']->id ?? null;

        if (! $reference || ! $contractId) {
            return null;
        }

        return Account::where('contract_id', $contractId)
            ->where('reference', $reference)
            ->first();
    }

    public function process(Import $import, array $mapped, array $raw, array $context = []): array
    {
        // Ensure contract context
        if (! isset($context['contract'])) {
            return [
                'action' => 'skipped',
                'message' => 'Account requires contract context',
            ];
        }

        // Fallback: if account.reference is empty, use contract.reference (matching v1 behavior)
        if (empty($mapped['reference'])) {
            $contractReference = $context['contract']['entity']->reference ?? null;
            if ($contractReference) {
                $mapped['reference'] = preg_replace('/\s+/', '', trim((string) $contractReference));
            }
        }

        $contractId = $context['contract']['entity']->id;
        $mapped['contract_id'] = $contractId;

        $existing = $this->resolve($mapped, $context);

        if ($existing) {
            // Track old balance for activity creation
            $oldBalance = (float) ($existing->balance_amount ?? 0);

            $payload = $this->buildPayload($mapped, $existing);
            $appliedFields = $this->trackAppliedFields($existing, $payload);

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

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

            // Create activity if balance changed and tracking is enabled
            if ($this->getOption('track_balance_changes', true) && array_key_exists('balance_amount', $appliedFields)) {
                $this->createBalanceChangeActivity($existing, $oldBalance, $import, $context);
            }

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

        // Create new account
        $account = new Account;
        $payload = $this->buildPayload($mapped, $account);
        
        // Ensure required defaults for new accounts
        if (!isset($payload['type_id'])) {
            $payload['type_id'] = $this->getDefaultAccountTypeId();
        }
        
        $account->fill($payload);
        $account->save();

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

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

        $fieldMap = [
            'contract_id' => 'contract_id',
            'reference' => 'reference',
            'title' => 'title',
            'description' => 'description',
            'balance_amount' => 'balance_amount',
            'currency' => 'currency',
        ];

        foreach ($fieldMap as $source => $target) {
            if (array_key_exists($source, $mapped)) {
                $value = $mapped[$source];
                
                // Normalize decimal fields (convert comma to period)
                if (in_array($source, ['balance_amount', 'initial_amount']) && is_string($value)) {
                    $value = DecimalNormalizer::normalize($value);
                }
                
                $payload[$target] = $value;
            }
        }

        return $payload;
    }

    /**
     * Create activity when account balance changes.
     */
    protected function createBalanceChangeActivity(Account $account, float $oldBalance, Import $import, array $context): void
    {
        if (! $this->getOption('create_activity_on_balance_change', true)) {
            return;
        }

        try {
            $newBalance = (float) ($account->balance_amount ?? 0);

            // Skip if balance didn't actually change
            if ($newBalance === $oldBalance) {
                return;
            }

            $currency = \App\Models\PaymentSetting::first()?->default_currency ?? 'EUR';
            $beforeStr = number_format($oldBalance, 2, ',', '.').' '.$currency;
            $afterStr = number_format($newBalance, 2, ',', '.').' '.$currency;
            $note = 'Sprememba stanja (Stanje pred: '.$beforeStr.', Stanje po: '.$afterStr.'; Izvor: sprememba)';

            // Get client_case_id
            $clientCaseId = $account->contract?->client_case_id;

            if ($clientCaseId) {
                // Use action_id from import meta if available
                $metaActionId = (int) ($import->meta['action_id'] ?? 0);

                if ($metaActionId > 0) {
                    \App\Models\Activity::create([
                        'due_date' => null,
                        'amount' => null,
                        'note' => $note,
                        'action_id' => $metaActionId,
                        'decision_id' => $import->meta['decision_id'] ?? null,
                        'client_case_id' => $clientCaseId,
                        'contract_id' => $account->contract_id,
                    ]);
                }
            }
        } catch (\Throwable $e) {
            \Log::warning('Failed to create balance change activity', [
                'account_id' => $account->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Get default account type ID.
     */
    protected function getDefaultAccountTypeId(): int
    {
        return (int) (\App\Models\AccountType::min('id') ?? 1);
    }
}