import { Injectable } from '@nestjs/common';

export interface DetectedFields {
  contactName?: string;
  contactPhone?: string;
  contactEmail?: string;
  title?: string;
  message?: string;
  customFields: Record<string, any>;
  rawFields: Record<string, any>;
}

// Priority 2: Field name patterns (RU + EN)
const PHONE_NAMES = new Set([
  'phone',
  'tel',
  'telephone',
  'mobile',
  'contact_phone',
  'phone_number',
  'phonenumber',
  'cellphone',
  'cell',
  'телефон',
  'тел',
  'мобильный',
  'номер_телефона',
]);

const NAME_NAMES = new Set([
  'name',
  'first_name',
  'firstname',
  'fio',
  'client_name',
  'full_name',
  'fullname',
  'contact_name',
  'contactname',
  'user_name',
  'username',
  'имя',
  'фио',
  'клиент',
  'контакт',
  'имя_клиента',
]);

const EMAIL_NAMES = new Set([
  'email',
  'mail',
  'e-mail',
  'e_mail',
  'contact_email',
  'почта',
  'электронная_почта',
  'емейл',
  'емайл',
]);

const TITLE_NAMES = new Set([
  'subject',
  'title',
  'тема',
  'заголовок',
  'comment',
  'комментарий',
  'message',
  'сообщение',
]);

// Priority 3: Value regex patterns
const PHONE_REGEX = /^[+]?[78]?\s?[(]?\d{3}[)]?\s?\d{3}[-\s]?\d{2}[-\s]?\d{2}$/;
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const NAME_REGEX = /^[А-ЯЁA-Z][а-яёa-z]+(\s[А-ЯЁA-Z][а-яёa-z]+){0,2}$/;

// UTM & analytics keys
const UTM_KEYS = new Set(['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term']);

const ANALYTICS_KEYS: Record<string, string> = {
  _ym_uid: 'ym_uid',
  _ym_counter: 'ym_counter',
  yclid: 'yclid',
  _ga: 'ga',
  _gid: 'gid',
  gclid: 'gclid',
  fbclid: 'fbclid',
  roistat_visit: 'roistat_visit',
  calltouch_session: 'calltouch_session',
  comagic_id: 'comagic_id',
};

@Injectable()
export class FieldDetectorService {
  /**
   * Detect fields from raw payload.
   * Priority: 1. fieldMapping → 2. name match → 3. regex → 4. rawFields
   */
  detect(
    payload: Record<string, any>,
    fieldMapping?: Record<string, string> | null,
    listMapping?: Record<string, Record<string, string>> | null,
  ): {
    fields: DetectedFields;
    utm: Record<string, string>;
    analytics: Record<string, string>;
  } {
    const fields: DetectedFields = {
      customFields: {},
      rawFields: {},
    };
    const utm: Record<string, string> = {};
    const analytics: Record<string, string> = {};

    const flatPayload = this.flatten(payload);

    for (const [key, value] of Object.entries(flatPayload)) {
      if (value === null || value === undefined || value === '') continue;
      const strValue = String(value);
      const lowerKey = key.toLowerCase().trim();

      // Extract UTM
      if (UTM_KEYS.has(lowerKey)) {
        utm[lowerKey.replace('utm_', '')] = strValue;
        continue;
      }

      // Extract analytics
      if (ANALYTICS_KEYS[lowerKey]) {
        analytics[ANALYTICS_KEYS[lowerKey]] = strValue;
        continue;
      }

      // Priority 1: Configured field mapping
      if (fieldMapping && fieldMapping[key]) {
        const targetField = fieldMapping[key];
        const resolvedValue = this.resolveListValue(targetField, strValue, listMapping);
        this.assignField(fields, targetField, resolvedValue);
        continue;
      }

      // Priority 2: Name-based detection
      if (!fields.contactPhone && PHONE_NAMES.has(lowerKey)) {
        fields.contactPhone = this.normalizePhone(strValue);
        continue;
      }
      if (!fields.contactName && NAME_NAMES.has(lowerKey)) {
        fields.contactName = strValue;
        continue;
      }
      if (!fields.contactEmail && EMAIL_NAMES.has(lowerKey)) {
        fields.contactEmail = strValue.toLowerCase();
        continue;
      }
      if (!fields.title && TITLE_NAMES.has(lowerKey)) {
        fields.title = strValue;
        continue;
      }

      // Priority 3: Regex-based detection
      if (!fields.contactPhone && PHONE_REGEX.test(strValue)) {
        fields.contactPhone = this.normalizePhone(strValue);
        continue;
      }
      if (!fields.contactEmail && EMAIL_REGEX.test(strValue)) {
        fields.contactEmail = strValue.toLowerCase();
        continue;
      }
      if (!fields.contactName && NAME_REGEX.test(strValue)) {
        fields.contactName = strValue;
        continue;
      }

      // Priority 4: Raw fields
      fields.rawFields[key] = value;
    }

    return { fields, utm, analytics };
  }

  /** Flatten nested objects: { a: { b: 1 } } → { "a.b": 1 } */
  private flatten(obj: Record<string, any>, prefix = ''): Record<string, any> {
    const result: Record<string, any> = {};
    for (const [key, value] of Object.entries(obj)) {
      const fullKey = prefix ? `${prefix}.${key}` : key;
      if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
        Object.assign(result, this.flatten(value, fullKey));
      } else {
        result[fullKey] = value;
      }
    }
    return result;
  }

  /** Resolve list field values via mapping or text match */
  private resolveListValue(
    targetField: string,
    value: string,
    listMapping?: Record<string, Record<string, string>> | null,
  ): string {
    if (!listMapping || !listMapping[targetField]) return value;
    const mapping = listMapping[targetField];
    // Direct ID → text mapping
    if (mapping[value]) return mapping[value];
    // Case-insensitive text match
    const lowerValue = value.toLowerCase();
    for (const [, text] of Object.entries(mapping)) {
      if (text.toLowerCase() === lowerValue) return text;
    }
    return value;
  }

  /** Normalize Russian phone to +7XXXXXXXXXX */
  private normalizePhone(phone: string): string {
    const digits = phone.replace(/\D/g, '');
    if (digits.length === 11 && digits.startsWith('8')) {
      return '+7' + digits.slice(1);
    }
    if (digits.length === 11 && digits.startsWith('7')) {
      return '+' + digits;
    }
    if (digits.length === 10) {
      return '+7' + digits;
    }
    return phone;
  }

  /** Assign detected value to the right field */
  private assignField(fields: DetectedFields, targetField: string, value: string): void {
    switch (targetField) {
      case 'contactPhone':
        fields.contactPhone = this.normalizePhone(value);
        break;
      case 'contactName':
        fields.contactName = value;
        break;
      case 'contactEmail':
        fields.contactEmail = value.toLowerCase();
        break;
      case 'title':
        fields.title = value;
        break;
      case 'message':
        fields.message = value;
        break;
      default:
        // Custom field
        fields.customFields[targetField] = value;
        break;
    }
  }
}
