import { env } from "../config/env.js";
import { getLatestSemanticAnalysis, type SemanticAnalysisRun } from "../analysis/semanticAnalysis.js";
import { collectWordstatEvidence, getLatestWordstatEvidence, type WordstatEvidence } from "./wordstatRepository.js";
import { createWordstatProvider } from "./wordstatProvider.js";

type MarketProviderId = "model" | "serp" | "text_quality" | "wordstat";
type MarketProviderStatus = "connected" | "disabled" | "not_configured" | "not_implemented";
type MarketEnrichmentState = "not_ready" | "not_collected" | "not_configured" | "partial_ready";
type MarketEvidenceStatus =
  | "collection_failed"
  | "collected"
  | "collected_no_signal"
  | "collected_related_only"
  | "deterministic_only"
  | "not_collected"
  | "not_configured"
  | "ready_for_collection";

type MarketProviderDescriptor = {
  id: MarketProviderId;
  label: string;
  role: string;
  status: MarketProviderStatus;
  mode: string;
  userActionRequired: boolean;
  platformActionRequired: boolean;
  message: string;
};

export type MarketEnrichmentContract = {
  schemaVersion: "market-enrichment.v1";
  projectId: string;
  semanticRunId: string | null;
  generatedAt: string;
  state: MarketEnrichmentState;
  readiness: {
    canCollectWordstat: boolean;
    canCollectSerp: boolean;
    seedCount: number;
    briefCount: number;
    configuredProviderCount: number;
    userSetupRequired: boolean;
  };
  providers: MarketProviderDescriptor[];
  seedQueue: Array<{
    phrase: string;
    clusterId: string;
    clusterTitle: string;
    priority: "high" | "medium" | "low";
    source: "detected" | "ontology";
    evidenceStatus: MarketEvidenceStatus;
    targetProviders: MarketProviderId[];
    blocker: string | null;
    frequency: number | null;
    frequencyGroup: string | null;
    relatedCount: number;
    lastCollectedAt: string | null;
  }>;
  briefEvidence: Array<{
    path: string;
    priority: "high" | "medium" | "low";
    action: "create" | "strengthen" | "validate";
    qualityScore: number | null;
    qualityLevel: "blocked" | "needs_work" | "ready" | null;
    seedPhrases: string[];
    evidenceStatus: MarketEvidenceStatus;
    requiredProviders: MarketProviderId[];
    missingEvidence: string[];
  }>;
  wordstat: WordstatEvidence;
  nextActions: string[];
};

function isSerpConfigured() {
  const config = env.marketProviders.serp;

  return config.provider !== "disabled" && Boolean(config.apiBaseUrl && config.hasApiToken);
}

async function buildProviderRegistry(): Promise<MarketProviderDescriptor[]> {
  const serpConfig = env.marketProviders.serp;
  const wordstatStatus = (await createWordstatProvider()).getStatus();
  const serpConfigured = isSerpConfigured();

  return [
    {
      id: "wordstat",
      label: "Yandex Wordstat",
      role: "Частотность, похожие запросы, региональные и сезонные сигналы по seed-фразам.",
      status: wordstatStatus.connected ? "connected" : "not_configured",
      mode: wordstatStatus.mode,
      userActionRequired: false,
      platformActionRequired: !wordstatStatus.connected,
      message: wordstatStatus.connected
        ? wordstatStatus.message
        : `${wordstatStatus.message} Пользовательский сценарий не должен требовать ручной настройки MCP.`
    },
    {
      id: "serp",
      label: "Yandex SERP",
      role: "Типы страниц в выдаче, конкурентные углы, сложность и сниппеты.",
      status: serpConfigured ? "connected" : "not_configured",
      mode: serpConfig.provider,
      userActionRequired: false,
      platformActionRequired: !serpConfigured,
      message: serpConfigured
        ? "SERP provider настроен; можно собирать конкурентные evidence."
        : "SERP provider ещё не настроен; deterministic analysis не должен притворяться рыночной проверкой."
    },
    {
      id: "model",
      label: "Model Provider",
      role: "Классификация неоднозначных фраз, интентов и конкурентных формулировок.",
      status: "not_implemented",
      mode: "provider_abstraction",
      userActionRequired: false,
      platformActionRequired: true,
      message: "Model provider будет подключаться платформенно через общий AI layer; в MVP решение не просит пользователя о ключах."
    },
    {
      id: "text_quality",
      label: "Text Quality",
      role: "Локальная проверка заспамленности, воды и перебора ключей после рерайта.",
      status: "not_implemented",
      mode: "local_ru_text",
      userActionRequired: false,
      platformActionRequired: true,
      message: "Text.ru API не подключается; по ТЗ нужен локальный quality checker по аналогичной модели показателей."
    }
  ];
}

function getProviderStatus(providers: MarketProviderDescriptor[], id: MarketProviderId) {
  return providers.find((provider) => provider.id === id)?.status ?? "not_configured";
}

function getEvidenceStatus(providers: MarketProviderDescriptor[], requiredProviders: MarketProviderId[]): MarketEvidenceStatus {
  if (requiredProviders.length === 0) {
    return "deterministic_only";
  }

  const statuses = requiredProviders.map((providerId) => getProviderStatus(providers, providerId));

  if (statuses.some((status) => status === "not_configured" || status === "disabled")) {
    return "not_configured";
  }

  if (statuses.every((status) => status === "connected")) {
    return "ready_for_collection";
  }

  return "not_collected";
}

function getSeedBlocker(evidenceStatus: MarketEvidenceStatus) {
  if (evidenceStatus === "not_configured") {
    return "Нужен платформенный Wordstat provider; пользователь не должен вручную подключать MCP или внешний аккаунт.";
  }

  if (evidenceStatus === "collection_failed") {
    return "Последний Wordstat job упал; смотри provider error и raw job status в dev-mode.";
  }

  if (
    evidenceStatus === "ready_for_collection" ||
    evidenceStatus === "collected" ||
    evidenceStatus === "collected_related_only" ||
    evidenceStatus === "collected_no_signal"
  ) {
    return null;
  }

  return "Сбор ещё не запускался.";
}

function normalizePhrase(value: string) {
  return value.trim().replace(/\s+/g, " ").toLowerCase();
}

function buildWordstatSeedMap(wordstat: WordstatEvidence) {
  return new Map(wordstat.seedResults.map((result) => [normalizePhrase(result.phrase), result]));
}

function getSeedEvidenceStatus(
  providers: MarketProviderDescriptor[],
  wordstat: WordstatEvidence,
  wordstatResult: WordstatEvidence["seedResults"][number] | undefined
): MarketEvidenceStatus {
  if (wordstatResult?.frequency !== null && wordstatResult?.frequency !== undefined) {
    return "collected";
  }

  if (wordstat.latestJob?.status === "failed") {
    return "collection_failed";
  }

  if (wordstat.latestJob?.status === "done" && wordstatResult && wordstatResult.relatedCount > 0) {
    return "collected_related_only";
  }

  if (wordstat.latestJob?.status === "done") {
    return "collected_no_signal";
  }

  return getEvidenceStatus(providers, ["wordstat"]);
}

function buildSeedQueue(analysis: SemanticAnalysisRun, providers: MarketProviderDescriptor[], wordstat: WordstatEvidence) {
  const wordstatResults = buildWordstatSeedMap(wordstat);

  return analysis.seedCandidates.slice(0, 80).map((seed) => {
    const targetProviders: MarketProviderId[] = ["wordstat"];
    const result = wordstatResults.get(normalizePhrase(seed.phrase));
    const evidenceStatus = getSeedEvidenceStatus(providers, wordstat, result);

    return {
      phrase: seed.phrase,
      clusterId: seed.clusterId,
      clusterTitle: seed.clusterTitle,
      priority: seed.priority,
      source: seed.source,
      evidenceStatus,
      targetProviders,
      blocker: getSeedBlocker(evidenceStatus),
      frequency: result?.frequency ?? null,
      frequencyGroup: result?.frequencyGroup ?? null,
      relatedCount: result?.relatedCount ?? 0,
      lastCollectedAt: result?.collectedAt ?? null
    };
  });
}

function buildBriefEvidence(analysis: SemanticAnalysisRun, providers: MarketProviderDescriptor[]) {
  return (analysis.landingPageBriefs ?? []).slice(0, 80).map((brief) => {
    const requiredProviders: MarketProviderId[] = ["wordstat", "serp"];
    const evidenceStatus = getEvidenceStatus(providers, requiredProviders);

    return {
      path: brief.path,
      priority: brief.priority,
      action: brief.action,
      qualityScore: brief.qualityContract?.score ?? null,
      qualityLevel: brief.qualityContract?.level ?? null,
      seedPhrases: brief.seedPhrases.slice(0, 8),
      evidenceStatus,
      requiredProviders,
      missingEvidence: brief.qualityContract?.missingEvidence ?? [
        "Wordstat частотность и сезонность",
        "SERP-конкуренты и типы страниц",
        "Региональная выдача"
      ]
    };
  });
}

function getEnrichmentState(
  analysis: SemanticAnalysisRun | null,
  providers: MarketProviderDescriptor[],
  seedCount: number,
  wordstat: WordstatEvidence
): MarketEnrichmentState {
  if (!analysis) {
    return "not_ready";
  }

  if (seedCount === 0) {
    return "not_ready";
  }

  if (getProviderStatus(providers, "wordstat") !== "connected") {
    return "not_configured";
  }

  if (wordstat.latestJob?.status === "done" && wordstat.summary.collectedSeedCount > 0) {
    return getProviderStatus(providers, "serp") === "connected" ? "not_collected" : "partial_ready";
  }

  if (getProviderStatus(providers, "serp") !== "connected") {
    return "partial_ready";
  }

  return "not_collected";
}

function buildNextActions(contract: Omit<MarketEnrichmentContract, "nextActions">) {
  const actions: string[] = [];

  if (!contract.semanticRunId) {
    actions.push("Сначала запустить semantic analysis: без seed candidates market layer не стартует.");
    return actions;
  }

  const wordstat = contract.providers.find((provider) => provider.id === "wordstat");
  const serp = contract.providers.find((provider) => provider.id === "serp");

  if (wordstat?.status !== "connected") {
    actions.push("Настроить платформенный Wordstat provider: MCP-KV endpoint или прямой API adapter на backend.");
  } else if (contract.wordstat.latestJob?.status === "done") {
    actions.push(
      `Wordstat evidence собрано: ${contract.wordstat.summary.collectedSeedCount} seed-фраз, ${contract.wordstat.summary.resultCount} rows. Следующий слой — keywordService cleaning.`
    );
  } else if (contract.wordstat.latestJob?.status === "failed") {
    actions.push("Проверить Wordstat provider: последний job завершился ошибкой, raw/error сохранены в dev-mode contract.");
  } else if (contract.readiness.seedCount > 0) {
    actions.push(`Запустить Wordstat collection для ${contract.readiness.seedCount} seed-фраз.`);
  }

  if (serp?.status !== "connected") {
    actions.push("Настроить платформенный SERP provider для конкурентных evidence, без ручной работы пользователя.");
  }

  if (wordstat?.status !== "connected" && contract.readiness.seedCount > 0) {
    actions.push(`После настройки провайдера отправить ${contract.readiness.seedCount} seed-фраз в Wordstat queue.`);
  }

  actions.push("Хранить внешние результаты как evidence при seed/brief/page, а не смешивать их с deterministic-анализом.");

  return actions;
}

export async function getMarketEnrichmentContract(projectId: string): Promise<MarketEnrichmentContract> {
  const analysis = await getLatestSemanticAnalysis(projectId);
  const providers = await buildProviderRegistry();
  const wordstat = await getLatestWordstatEvidence(projectId, analysis?.runId ?? null);
  const seedQueue = analysis ? buildSeedQueue(analysis, providers, wordstat) : [];
  const briefEvidence = analysis ? buildBriefEvidence(analysis, providers) : [];
  const configuredProviderCount = providers.filter((provider) => provider.status === "connected").length;
  const contractWithoutActions: Omit<MarketEnrichmentContract, "nextActions"> = {
    schemaVersion: "market-enrichment.v1",
    projectId,
    semanticRunId: analysis?.runId ?? null,
    generatedAt: new Date().toISOString(),
    state: getEnrichmentState(analysis, providers, seedQueue.length, wordstat),
    readiness: {
      canCollectWordstat:
        getProviderStatus(providers, "wordstat") === "connected" &&
        seedQueue.length > 0 &&
        wordstat.latestJob?.status !== "running",
      canCollectSerp: getProviderStatus(providers, "serp") === "connected" && briefEvidence.length > 0,
      seedCount: seedQueue.length,
      briefCount: briefEvidence.length,
      configuredProviderCount,
      userSetupRequired: providers.some((provider) => provider.userActionRequired)
    },
    providers,
    seedQueue,
    briefEvidence,
    wordstat
  };

  return {
    ...contractWithoutActions,
    nextActions: buildNextActions(contractWithoutActions)
  };
}

export async function runMarketEnrichment(projectId: string): Promise<MarketEnrichmentContract> {
  const analysis = await getLatestSemanticAnalysis(projectId);
  const providers = await buildProviderRegistry();

  if (!analysis || getProviderStatus(providers, "wordstat") !== "connected" || analysis.seedCandidates.length === 0) {
    return getMarketEnrichmentContract(projectId);
  }

  try {
    await collectWordstatEvidence(projectId, analysis);
  } catch (error) {
    console.error(error);
  }

  return getMarketEnrichmentContract(projectId);
}
