<?php

namespace Modules\Sale\Services;

use App\Models\LeadScoringRuleModel;

class LeadScoringService
{
    protected LeadScoringRuleModel $rules;

    public function __construct()
    {
        $this->rules = new LeadScoringRuleModel();
    }

    public function calculateScore(array $lead): int
    {
        $score = 0;

        foreach ($this->rules->getActive() as $rule) {
            if ($this->ruleMatches($lead, $rule)) {
                $score += (int) $rule['points'];
            }
        }

        return max(0, $score);
    }

    public function recalculateAll(): int
    {
        $leads  = (new \App\Models\LeadModel())->where('status !=', 'converted')->findAll();
        $leadModel = new \App\Models\LeadModel();
        $updated = 0;

        foreach ($leads as $lead) {
            $score = $this->calculateScore($lead);
            if ((int) $lead['score'] !== $score) {
                $leadModel->update($lead['id'], ['score' => $score]);
                $updated++;
            }
        }

        return $updated;
    }

    protected function ruleMatches(array $lead, array $rule): bool
    {
        $criterion = $rule['criterion'];
        $operator  = $rule['operator'];
        $value     = $rule['value'];

        return match ($criterion) {
            'has_email'       => $this->evaluateIsSet($lead['email'] ?? null, $operator),
            'has_phone'       => $this->evaluateIsSet($lead['phone'] ?? null, $operator),
            'has_company'     => $this->evaluateIsSet($lead['company_name'] ?? null, $operator),
            'source'          => $this->evaluateEquals((string) ($lead['lead_source_id'] ?? ''), $operator, $value),
            'estimated_value' => $this->evaluateNumeric((float) ($lead['estimated_value'] ?? 0), $operator, (float) ($value ?? 0)),
            'priority'        => $this->evaluateEquals($lead['priority'] ?? '', $operator, $value),
            default           => false,
        };
    }

    protected function evaluateIsSet(?string $fieldValue, string $operator): bool
    {
        $isSet = trim((string) $fieldValue) !== '';

        return $operator === 'is_set' ? $isSet : ! $isSet;
    }

    protected function evaluateEquals(string $actual, string $operator, ?string $expected): bool
    {
        $match = strcasecmp(trim($actual), trim((string) $expected)) === 0;

        return $operator === 'not_equals' ? ! $match : $match;
    }

    protected function evaluateNumeric(float $actual, string $operator, float $expected): bool
    {
        return match ($operator) {
            'greater_than' => $actual > $expected,
            'less_than'    => $actual < $expected,
            'equals'       => abs($actual - $expected) < 0.01,
            'not_equals'   => abs($actual - $expected) >= 0.01,
            default        => false,
        };
    }
}
