<?php
namespace App\Services;

use App\Repositories\AiRepository;
use RuntimeException;
use Throwable;

class AiRecommendationService
{
    private OpenAiService $openAi;
    private AiPromptService $prompts;
    private AiRepository $requests;

    private const FEATURES = [
        'chat',
        'customer_brief',
        'deal_risk',
        'activity_draft',
        'kpi_explain',
        'operation_rule_draft',
    ];

    private const OPERATION_FILTER_KEYS = [
        'owner_didar_id',
        'previous_owner_id',
        'sale_status',
        'deal_status',
        'pool_key',
        'owner_didar_ids',
        'no_owner',
        'search',
        'lead_date_from',
        'lead_date_to',
        'last_deal_from',
        'last_deal_to',
        'last_activity_from',
        'last_activity_to',
        'last_payment_from',
        'last_payment_to',
        'deal_older_than_days',
        'has_payment',
    ];

    private const OPERATION_CONDITION_FIELDS = [
        'last_deal_at',
        'lead_registered_at',
        'last_activity_at',
        'last_payment_at',
        'has_any_payment',
        'last_deal_status',
        'sale_status',
        'owner_empty',
        'pool_key',
    ];

    private const OPERATION_TYPES = [
        'change_owner',
        'move_lead_to_pool',
        'mark_last_deal_lost',
    ];

    public function __construct(OpenAiService $openAi, AiPromptService $prompts, AiRepository $requests)
    {
        $this->openAi = $openAi;
        $this->prompts = $prompts;
        $this->requests = $requests;
    }

    public function run(string $featureKey, array $context, string $entityType = '', string $entityId = ''): array
    {
        if (!in_array($featureKey, self::FEATURES, true)) {
            throw new RuntimeException('Unknown AI feature');
        }

        $sourceRefs = (array)($context['source_refs'] ?? []);
        $requestId = $this->requests->createRequest([
            'user_id' => (int)($_SESSION['user_id'] ?? 0),
            'user_didar_id' => (string)($_SESSION['didar_id'] ?? ''),
            'feature_key' => $featureKey,
            'entity_type' => $entityType,
            'entity_id' => $entityId,
            'prompt_version' => $this->prompts->promptVersion(),
            'model' => $this->openAi->model(),
            'input_summary' => $this->summarizeContext($context),
            'source_refs' => $sourceRefs,
        ]);

        try {
            $output = $this->openAi->createStructuredResponse(
                $this->prompts->systemPrompt($featureKey),
                $context,
                $this->prompts->schema($featureKey)
            );
            $output = $this->normalizeOutput($featureKey, $output);
            $this->requests->finishRequest($requestId, 'success', $output, $sourceRefs);
            return [
                'ai_request_id' => $requestId,
                'feature_key' => $featureKey,
                'model' => $this->openAi->model(),
                'result' => $output,
                'source_refs' => $sourceRefs,
            ];
        } catch (Throwable $e) {
            $this->requests->finishRequest($requestId, 'failed', [], $sourceRefs, $e->getMessage());
            throw $e;
        }
    }

    public function configured(): bool
    {
        return $this->openAi->isConfigured();
    }

    public function enabled(): bool
    {
        return $this->openAi->isEnabled();
    }

    private function normalizeOutput(string $featureKey, array $output): array
    {
        if ($featureKey === 'operation_rule_draft') {
            return $this->normalizeOperationRuleDraft($output);
        }
        return $output;
    }

    private function normalizeOperationRuleDraft(array $output): array
    {
        $warnings = array_values(array_filter(array_map('strval', (array)($output['warnings'] ?? []))));
        $filter = $this->allowKeys((array)($output['filter'] ?? []), self::OPERATION_FILTER_KEYS, $warnings, 'filter');
        $condition = $this->normalizeCondition((array)($output['condition'] ?? []), $warnings);
        $operation = $this->normalizeOperation((array)($output['operation'] ?? []), $warnings);

        $output['filter'] = $filter;
        $output['condition'] = $condition;
        $output['operation'] = $operation;
        $output['warnings'] = array_values(array_unique($warnings));
        $output['needs_human_review'] = true;

        return $output;
    }

    private function normalizeCondition(array $condition, array &$warnings): array
    {
        $rules = [];
        foreach ((array)($condition['all'] ?? []) as $rule) {
            if (!is_array($rule)) {
                continue;
            }
            $field = (string)($rule['field'] ?? '');
            if (!in_array($field, self::OPERATION_CONDITION_FIELDS, true)) {
                $warnings[] = 'Dropped unsupported condition field: ' . $field;
                continue;
            }
            $rules[] = [
                'field' => $field,
                'operator' => (string)($rule['operator'] ?? 'equals'),
                'value' => $rule['value'] ?? null,
            ];
        }

        return ['all' => $rules];
    }

    private function normalizeOperation(array $operation, array &$warnings): array
    {
        $actions = (array)($operation['actions'] ?? []);
        if (empty($actions) && isset($operation['type'])) {
            $actions = [$operation];
        }

        $normalized = [];
        foreach ($actions as $action) {
            if (!is_array($action)) {
                continue;
            }
            $type = (string)($action['type'] ?? '');
            if (!in_array($type, self::OPERATION_TYPES, true)) {
                $warnings[] = 'Dropped unsupported operation: ' . $type;
                continue;
            }
            $safeAction = [
                'type' => $type,
                'reason' => (string)($action['reason'] ?? 'AI drafted rule, human approval required'),
            ];
            if ($type === 'change_owner') {
                $safeAction['owner_didar_id'] = (string)($action['owner_didar_id'] ?? '');
                if ($safeAction['owner_didar_id'] === '') {
                    $warnings[] = 'change_owner requires owner_didar_id before saving the rule.';
                }
            } elseif ($type === 'move_lead_to_pool') {
                $safeAction['pool_key'] = (string)($action['pool_key'] ?? 'crm_leads');
            } elseif ($type === 'mark_last_deal_lost') {
                $safeAction['failure_reason'] = (string)($action['failure_reason'] ?? 'sales_agent_underperformance');
            }
            $normalized[] = $safeAction;
        }

        return ['actions' => $normalized];
    }

    private function allowKeys(array $input, array $allowed, array &$warnings, string $label): array
    {
        $result = [];
        foreach ($input as $key => $value) {
            $key = (string)$key;
            if (!in_array($key, $allowed, true)) {
                $warnings[] = 'Dropped unsupported ' . $label . ' key: ' . $key;
                continue;
            }
            $result[$key] = $value;
        }
        return $result;
    }

    private function summarizeContext(array $context): array
    {
        return [
            'context_type' => (string)($context['context_type'] ?? ''),
            'entity_type' => (string)($context['entity_type'] ?? ''),
            'entity_id' => (string)($context['entity_id'] ?? ''),
            'screen' => (string)($context['screen'] ?? ''),
            'source_ref_count' => count((array)($context['source_refs'] ?? [])),
        ];
    }
}
