export const supportedTypes = [
  {
    id: "ipv4",
    title: "IPv4",
    description: "Анализ адресов, запросы к AbuseIPDB, DB-IP, Kaspersky.",
    icon: "bi-hdd-network",
    tone: "primary",
  },
  {
    id: "domain",
    title: "Домен",
    description: "Категоризация, Top1M, WHOIS, ранги и ML-модель.",
    icon: "bi-globe2",
    tone: "info",
  },
  {
    id: "url",
    title: "URL",
    description: "Проверка через Kaspersky и HTTP-observer.",
    icon: "bi-link-45deg",
    tone: "success",
  },
  {
    id: "hash",
    title: "Хеши (MD5/SHA1/SHA256)",
    description: "Верификация загрузок и зона Kaspersky.",
    icon: "bi-shield-lock",
    tone: "warning",
  },
];

export const verdictPriority = [
  "Блокировка",
  "Мониторинг",
  "Ручная проверка",
  "Пропуск",
  "неизвестно",
];

export const verdictMeta = {
  неизвестно: { tone: "secondary", icon: "bi-question-circle", label: "Неизвестно" },
  Пропуск: { tone: "success", icon: "bi-dash-circle", label: "Пропуск" },
  "Ручная проверка": { tone: "warning", icon: "bi-search", label: "Ручная проверка" },
  Блокировка: { tone: "danger", icon: "bi-shield-x", label: "Блокировка" },
  Мониторинг: { tone: "info", icon: "bi-activity", label: "Мониторинг" },
};

export class IocStore {
  constructor() {
    this.entries = [];
  }

  normalizeVerdicts(verdicts = []) {
    const unique = Array.from(new Set(verdicts.length ? verdicts : ["неизвестно"]));
    const orderMap = new Map(verdictPriority.map((verdict, index) => [verdict, index]));

    return unique.sort((a, b) => {
      const rankA = orderMap.has(a) ? orderMap.get(a) : orderMap.size;
      const rankB = orderMap.has(b) ? orderMap.get(b) : orderMap.size;
      return rankA - rankB;
    });
  }

  getPrimaryVerdict(entry) {
    return entry.verdicts?.[0] || "неизвестно";
  }

  getVerdictRank(verdict) {
    const index = verdictPriority.indexOf(verdict);
    return index === -1 ? verdictPriority.length : index;
  }

  getGroupKey(verdicts = []) {
    return this.normalizeVerdicts(verdicts).join(" | ");
  }

  add(rawValue, category, verdicts = ["неизвестно"], reasons = [], features = null, tags = []) {
    const normalizedVerdicts = this.normalizeVerdicts(verdicts);
    const normalizedTags = Array.isArray(tags) ? tags : [];
    const existing = this.entries.find((entry) => entry.value === rawValue);
    if (existing) {
      existing.category = existing.category || category;
      existing.verdicts = normalizedVerdicts;
      existing.reasons = reasons;
      existing.features = features ?? existing.features;
      existing.tags = normalizedTags;
      return existing;
    }

    const entry = { value: rawValue, category, verdicts: normalizedVerdicts, reasons, features, tags: normalizedTags };
    this.entries.push(entry);
    return entry;
  }

  clear() {
    this.entries = [];
  }

  loadFromMatches(matches) {
    this.clear();
    Object.entries(matches || {}).forEach(([category, values]) => {
      values.forEach((value) => this.add(value, category));
    });
  }

  applyVerdicts(verdictMap) {
    Object.entries(verdictMap || {}).forEach(([indicator, payload]) => {
      const verdicts = this.normalizeVerdicts(payload?.verdicts);
      const reasons = payload?.reasons || [];
      this.add(indicator, payload?.category, verdicts, reasons, payload?.features, payload?.tags || []);
    });
  }

  loadSnapshot(entries = []) {
    this.clear();
    entries.forEach((entry) => {
      this.add(entry.value, entry.category, entry.verdicts, entry.reasons, entry.features, entry.tags);
    });
  }

  groupByVerdict(entries = this.entries) {
    const groups = new Map();
    const sortedEntries = [...entries].sort((a, b) => {
      const sizeDiff = (b.verdicts?.length || 0) - (a.verdicts?.length || 0);
      if (sizeDiff !== 0) {
        return sizeDiff;
      }

      const rankA = this.getVerdictRank(this.getPrimaryVerdict(a));
      const rankB = this.getVerdictRank(this.getPrimaryVerdict(b));
      if (rankA !== rankB) {
        return rankA - rankB;
      }

      return a.value.localeCompare(b.value, "ru");
    });

    sortedEntries.forEach((entry) => {
      const normalizedVerdicts = this.normalizeVerdicts(entry.verdicts);
      const key = this.getGroupKey(normalizedVerdicts);
      if (!groups.has(key)) {
        groups.set(key, { key, verdicts: normalizedVerdicts, entries: [] });
      }

      groups.get(key).entries.push(entry);
    });

    return Array.from(groups.values()).sort((a, b) => {
      const sizeDiff = b.verdicts.length - a.verdicts.length;
      if (sizeDiff !== 0) {
        return sizeDiff;
      }

      const rankA = this.getVerdictRank(a.verdicts[0]);
      const rankB = this.getVerdictRank(b.verdicts[0]);
      if (rankA !== rankB) {
        return rankA - rankB;
      }

      return a.key.localeCompare(b.key, "ru");
    });
  }

  countByVerdict() {
    return this.groupByVerdict().reduce((acc, group) => {
      acc[group.key] = group.entries.length;
      return acc;
    }, {});
  }
}

export class ApiClient {
  constructor(baseUrl = null) {
    this.baseUrl = baseUrl || (typeof window !== "undefined" ? window.location.origin : "http://localhost:8001");
    this.endpoints = {
      parseText: "/api/parse/text",
      tasks: "/api/tasks",
      status: (taskId) => `/api/tasks/${taskId}`,
      docs: "/api/docs",
      health: "/api/health",
    };
  }

  async request(path, options = {}) {
    const url = `${this.baseUrl}${path}`;
    const response = await fetch(url, {
      headers: { "Content-Type": "application/json" },
      ...options,
    });

    const bodyText = await response.text();
    let payload;

    try {
      payload = bodyText ? JSON.parse(bodyText) : {};
    } catch (error) {
      console.warn("[UI] Не удалось распарсить ответ API", error);
      payload = { raw: bodyText };
    }

    if (!response.ok) {
      const detail = payload?.detail || response.statusText;
      throw new Error(`API ${response.status}: ${detail}`);
    }

    return payload;
  }

  async ping() {
    const url = `${this.baseUrl}${this.endpoints.docs}`;
    const response = await fetch(url, { method: "GET" });
    return {
      ok: response.ok,
      status: response.status,
      statusText: response.statusText,
      url,
    };
  }

  async parseText(text) {
    return this.request(this.endpoints.parseText, {
      method: "POST",
      body: JSON.stringify({ text }),
    });
  }

  async enqueueTask(text) {
    return this.request(this.endpoints.tasks, {
      method: "POST",
      body: JSON.stringify({ text }),
    });
  }

  async getTaskStatus(taskId) {
    return this.request(this.endpoints.status(taskId), { method: "GET" });
  }

  async getHealth() {
    return this.request(this.endpoints.health, { method: "GET" });
  }
}
