<?php

namespace App\Support;

use App\Models\LeadRule;

class LeadRuleEvaluator
{
    /**
     * Decide the status a freshly credited lead should get. Starts from the
     * admin's configured default (approved by default, preserving legacy
     * behavior) and applies the first matching active rule.
     *
     * @param  array  $data  The postback data used to build the lead.
     */
    public static function statusFor(array $data): string
    {
        $default = self::toStatus(site_setting('leads_default_status', 'approved'));

        try {
            $rules = LeadRule::where('is_active', true)->orderBy('sort_order')->orderBy('id')->get();
        } catch (\Throwable $exception) {
            return $default;
        }

        foreach ($rules as $rule) {
            if (self::matches($rule, $data)) {
                return self::toStatus($rule->action);
            }
        }

        return $default;
    }

    /**
     * Map a rule action (approve|hold|reject) to a lead status
     * (approved|held|rejected). Anything unknown falls back to approved to
     * preserve the app's original always-approve behavior.
     */
    private static function toStatus(string $action): string
    {
        return match ($action) {
            'hold', 'held' => 'held',
            'reject', 'rejected' => 'rejected',
            default => 'approved',
        };
    }

    private static function matches(LeadRule $rule, array $data): bool
    {
        $subject = match ($rule->match_field) {
            'company' => $data['company'] ?? '',
            'offer_name' => $data['campaign_name'] ?? $data['offer_name'] ?? '',
            'offer_id' => $data['campaign_id'] ?? $data['offer_id'] ?? '',
            'user_id' => $data['user_id'] ?? '',
            'country' => $data['country_code'] ?? $data['country'] ?? '',
            'trx' => $data['trx'] ?? '',
            'points' => $data['amount'] ?? $data['points'] ?? '',
            'payout' => $data['payout'] ?? '',
            default => '',
        };

        $subject = mb_strtolower(trim((string) $subject));
        $value = mb_strtolower(trim((string) $rule->match_value));

        if ($value === '') {
            return false;
        }

        if (in_array($rule->match_operator, ['greater_than', 'greater_than_or_equal', 'less_than', 'less_than_or_equal'], true)) {
            if (!is_numeric($subject) || !is_numeric($value)) {
                return false;
            }

            return match ($rule->match_operator) {
                'greater_than' => (float) $subject > (float) $value,
                'greater_than_or_equal' => (float) $subject >= (float) $value,
                'less_than' => (float) $subject < (float) $value,
                'less_than_or_equal' => (float) $subject <= (float) $value,
            };
        }

        return $rule->match_operator === 'contains' ? str_contains($subject, $value) : $subject === $value;
    }
}
