<?php

namespace App\Services\AdvancedFilter;

use App\Services\ContactFieldRegistry;

/**
 * The single, hard allowlist of fields/operators the advanced campaign
 * recipient filter may reference. Nothing from a request is ever used
 * directly as a column or relation name — only as a lookup key into this
 * registry. Also the source of the field-picker menu shown in the UI, so
 * the frontend menu and the backend allowlist can never drift apart.
 */
class FilterFieldRegistry
{
    private const TYPE_OPERATORS = [
        'string'              => ['equals', 'not_equals', 'contains', 'not_contains', 'starts_with', 'ends_with', 'is_empty', 'is_not_empty'],
        'date'                 => ['equals', 'before', 'after', 'between', 'is_empty', 'is_not_empty'],
        'enum'                 => ['is', 'is_not', 'is_any_of', 'is_none_of'],
        'relation'             => ['has_any', 'has_all', 'has_none'],
        'activity'             => ['within_days', 'not_within_days', 'never'],
        'campaign_activity'    => ['sent', 'not_sent', 'opened', 'not_opened', 'clicked', 'not_clicked', 'bounced', 'unsubscribed'],
        'automation_activity'  => ['enrolled', 'not_enrolled', 'completed', 'not_completed'],
    ];

    public static function fields(): array
    {
        return [
            'contact.first_name'     => self::contactField('first_name', 'Contact'),
            'contact.last_name'      => self::contactField('last_name', 'Contact'),
            'contact.email'          => self::contactField('email', 'Contact'),
            'contact.address_line_1' => self::contactField('address_line_1', 'Contact'),

            'contact.prefix'         => self::contactField('prefix', 'Contact', 'General Properties'),
            'contact.phone'          => self::contactField('phone', 'Contact', 'General Properties'),
            'contact.date_of_birth'  => self::contactField('date_of_birth', 'Contact', 'General Properties', 'date'),
            'contact.address_line_2' => self::contactField('address_line_2', 'Contact', 'General Properties'),
            'contact.city'           => self::contactField('city', 'Contact', 'General Properties'),
            'contact.state'          => self::contactField('state', 'Contact', 'General Properties'),
            'contact.postal_code'    => self::contactField('postal_code', 'Contact', 'General Properties'),
            'contact.country'        => self::contactField('country', 'Contact', 'General Properties'),

            'activity.last_sent'      => ['category' => 'Contact Activities', 'label' => 'Last Email Sent', 'type' => 'activity', 'event_type' => 'sent'],
            'activity.last_open'      => ['category' => 'Contact Activities', 'label' => 'Last Email Open', 'type' => 'activity', 'event_type' => 'open'],
            'activity.last_clicked'   => ['category' => 'Contact Activities', 'label' => 'Last Email Clicked', 'type' => 'activity', 'event_type' => 'click'],
            'activity.campaign_email' => ['category' => 'Contact Activities', 'label' => 'Campaign Email', 'type' => 'campaign_activity'],
            'activity.automation'     => ['category' => 'Contact Activities', 'label' => 'Automation Activity', 'type' => 'automation_activity'],

            'segment.status'       => ['category' => 'Contact Segment', 'label' => 'Status', 'type' => 'enum', 'column' => 'status', 'allowed' => ['subscribed', 'unsubscribed', 'bounced', 'spam_reported']],
            'segment.contact_type' => ['category' => 'Contact Segment', 'label' => 'Type', 'type' => 'enum', 'column' => 'contact_type', 'allowed' => ['lead', 'prospect', 'customer', 'partner']],
            'segment.tags'         => ['category' => 'Contact Segment', 'label' => 'Tags', 'type' => 'relation', 'relation' => 'tags'],
            'segment.lists'        => ['category' => 'Contact Segment', 'label' => 'Lists', 'type' => 'relation', 'relation' => 'lists'],
        ];
    }

    public static function get(string $key): ?array
    {
        return self::fields()[$key] ?? null;
    }

    public static function operatorsFor(string $type): array
    {
        return self::TYPE_OPERATORS[$type] ?? [];
    }

    public static function isOperatorAllowed(string $type, string $operator): bool
    {
        return in_array($operator, self::operatorsFor($type), true);
    }

    /**
     * Field menu grouped for the UI's cascading picker, with each field's
     * allowed operators attached so the frontend never has to hardcode a
     * parallel type-to-operator map.
     */
    public static function menuTree(): array
    {
        $byCategory = [];

        foreach (self::fields() as $key => $field) {
            $category = $field['category'];
            $group    = $field['group'] ?? null;
            $entry    = [
                'key'       => $key,
                'label'     => $field['label'],
                'type'      => $field['type'],
                'operators' => self::operatorsFor($field['type']),
                'allowed'   => $field['allowed'] ?? null,
            ];

            $byCategory[$category] ??= ['category' => $category, 'fields' => [], 'groups' => []];

            if ($group) {
                $byCategory[$category]['groups'][$group] ??= ['label' => $group, 'fields' => []];
                $byCategory[$category]['groups'][$group]['fields'][] = $entry;
            } else {
                $byCategory[$category]['fields'][] = $entry;
            }
        }

        return array_map(function ($category) {
            $category['groups'] = array_values($category['groups']);

            return $category;
        }, array_values($byCategory));
    }

    private static function contactField(string $column, string $category, ?string $group = null, string $type = 'string'): array
    {
        return array_filter([
            'category' => $category,
            'group'    => $group,
            'label'    => ContactFieldRegistry::FIELDS[$column]['label'] ?? ucfirst(str_replace('_', ' ', $column)),
            'type'     => $type,
            'column'   => $column,
        ], fn ($v) => $v !== null);
    }
}
