import { computed, onMounted, ref } from 'vue'

import { useAwardsStore } from '../../stores/awards'
import type {
  AdminTrackingFlagRule,
  AdminTrackingMetricRule,
  AdminTrackingRulesResponse,
  AdminTrackingSource,
} from '../../types/awards'

function cloneMetricRules(rules: AdminTrackingMetricRule[]) {
  return rules.map((rule) => ({
    ...rule,
    autoSupportedWindowKeys: [...(rule.autoSupportedWindowKeys ?? [])],
    ignoredCategories: [...(rule.ignoredCategories ?? [])],
  }))
}

function cloneFlagRules(rules: AdminTrackingFlagRule[]) {
  return rules.map((rule) => ({ ...rule }))
}

function normalizeMetricRule(rule: AdminTrackingMetricRule): AdminTrackingMetricRule {
  const autoSupportedWindowKeys = Array.isArray(rule.autoSupportedWindowKeys)
    ? [...new Set(rule.autoSupportedWindowKeys.map((item) => String(item).trim()).filter(Boolean))]
    : []

  return {
    ...rule,
    enabled: Boolean(rule.enabled),
    requiredForAutoClassification: Boolean(rule.requiredForAutoClassification),
    showInReview: Boolean(rule.showInReview),
    showInAdminSummary: Boolean(rule.showInAdminSummary),
    manualOverrideAllowed: Boolean(rule.manualOverrideAllowed),
    windowKey: String(rule.windowKey || '30d'),
    autoSupportedWindowKeys,
    providerFieldKey: rule.providerFieldKey?.trim() || null,
    topCount: rule.topCount == null ? null : Number(rule.topCount),
    minPrimaryCategorySharePercent: rule.minPrimaryCategorySharePercent == null ? null : Number(rule.minPrimaryCategorySharePercent),
    minPrimaryCategoryHours: rule.minPrimaryCategoryHours == null ? null : Number(rule.minPrimaryCategoryHours),
    maxDistinctCategoriesBeforeFlag: rule.maxDistinctCategoriesBeforeFlag == null ? null : Number(rule.maxDistinctCategoriesBeforeFlag),
    ignoredCategories: Array.isArray(rule.ignoredCategories)
      ? [...new Set(rule.ignoredCategories.map((item) => String(item).trim()).filter(Boolean))]
      : [],
    matchAwardCategoryAgainstTopCategories: Boolean(rule.matchAwardCategoryAgainstTopCategories),
    flagIfAwardCategoryNotInTopX: Boolean(rule.flagIfAwardCategoryNotInTopX),
    flagIfCategorySpreadTooWide: Boolean(rule.flagIfCategorySpreadTooWide),
    flagIfNoCategoryContextAvailable: Boolean(rule.flagIfNoCategoryContextAvailable),
    minValue: rule.minValue == null ? null : Number(rule.minValue),
    maxValue: rule.maxValue == null ? null : Number(rule.maxValue),
  }
}

function normalizeFlagRule(rule: AdminTrackingFlagRule): AdminTrackingFlagRule {
  return {
    ...rule,
    enabled: Boolean(rule.enabled),
    autoTriggerEnabled: Boolean(rule.autoTriggerEnabled),
    requiresManualReview: Boolean(rule.requiresManualReview),
    blocksApproval: false,
    adminNoteRequiredOnOverride: Boolean(rule.adminNoteRequiredOnOverride),
    severity: rule.severity === 'high' || rule.severity === 'low' ? rule.severity : 'medium',
  }
}

function createEmptyTrackingRules(): AdminTrackingRulesResponse {
  return {
    source: {
      providerKey: 'twitchtracker',
      providerLabel: 'TwitchTracker Basic API',
      baseUrl: 'https://twitchtracker.com/api',
      notesSummary: '',
      showManualReviewNotesInReview: true,
    },
    importantMetrics: [],
    optionalMetrics: [],
    flags: [],
    manualReviewNotes: '',
  }
}

function createSourceSnapshot(source: AdminTrackingSource) {
  return JSON.stringify(source)
}

function parseSourceSnapshot(snapshot: string): AdminTrackingSource {
  if (!snapshot) {
    return createEmptyTrackingRules().source
  }

  try {
    const parsed = JSON.parse(snapshot) as AdminTrackingSource
    return {
      providerKey: parsed.providerKey || 'twitchtracker',
      providerLabel: parsed.providerLabel || 'TwitchTracker Basic API',
      baseUrl: parsed.baseUrl || 'https://twitchtracker.com/api',
      notesSummary: parsed.notesSummary || '',
      showManualReviewNotesInReview: parsed.showManualReviewNotesInReview !== false,
    }
  } catch {
    return createEmptyTrackingRules().source
  }
}

function createRulesSnapshot(
  importantMetrics: AdminTrackingMetricRule[],
  optionalMetrics: AdminTrackingMetricRule[],
  flags: AdminTrackingFlagRule[],
) {
  return JSON.stringify({
    importantMetrics: importantMetrics.map(normalizeMetricRule),
    optionalMetrics: optionalMetrics.map(normalizeMetricRule),
    flags: flags.map(normalizeFlagRule),
  })
}

export function useAdminTrackingRules() {
  const store = useAwardsStore()
  const trackingLoading = ref(false)
  const rulesSaving = ref(false)
  const sourceSaving = ref(false)
  const notesSaving = ref(false)
  const trackingError = ref('')
  const trackingSuccess = ref('')
  const trackingSource = ref<AdminTrackingSource>(createEmptyTrackingRules().source)
  const importantMetrics = ref<AdminTrackingMetricRule[]>([])
  const optionalMetrics = ref<AdminTrackingMetricRule[]>([])
  const trackingFlags = ref<AdminTrackingFlagRule[]>([])
  const manualReviewNotes = ref('')
  const sourceSnapshot = ref('')
  const rulesSnapshot = ref('')
  const notesSnapshot = ref('')

  const trackingSummary = computed(() => ({
    importantActive: importantMetrics.value.filter((item) => item.enabled).length,
    optionalActive: optionalMetrics.value.filter((item) => item.enabled).length,
    flagsActive: trackingFlags.value.filter((item) => item.enabled).length,
    manualReviewFlags: trackingFlags.value.filter((item) => item.enabled && item.requiresManualReview).length,
  }))

  const hasUnsavedTrackingSourceChanges = computed(() => createSourceSnapshot(trackingSource.value) !== sourceSnapshot.value)
  const hasUnsavedTrackingRuleChanges = computed(() =>
    createRulesSnapshot(importantMetrics.value, optionalMetrics.value, trackingFlags.value) !== rulesSnapshot.value,
  )
  const hasUnsavedTrackingNotesChanges = computed(() => manualReviewNotes.value !== notesSnapshot.value)

  function applyResponse(response: AdminTrackingRulesResponse) {
    trackingSource.value = {
      providerKey: response.source?.providerKey || 'twitchtracker',
      providerLabel: response.source?.providerLabel || 'TwitchTracker Basic API',
      baseUrl: response.source?.baseUrl || 'https://twitchtracker.com/api',
      notesSummary: response.source?.notesSummary || '',
      showManualReviewNotesInReview: response.source?.showManualReviewNotesInReview !== false,
    }
    importantMetrics.value = cloneMetricRules(response.importantMetrics)
    optionalMetrics.value = cloneMetricRules(response.optionalMetrics)
    trackingFlags.value = cloneFlagRules(response.flags)
    manualReviewNotes.value = response.manualReviewNotes ?? ''
    sourceSnapshot.value = createSourceSnapshot(trackingSource.value)
    rulesSnapshot.value = createRulesSnapshot(importantMetrics.value, optionalMetrics.value, trackingFlags.value)
    notesSnapshot.value = manualReviewNotes.value
  }

  async function loadTrackingRules() {
    trackingLoading.value = true
    trackingError.value = ''
    trackingSuccess.value = ''
    try {
      applyResponse(await store.loadAdminTrackingRules())
    } catch (error) {
      trackingError.value = error instanceof Error ? error.message : 'Tracking Rules konnten nicht geladen werden.'
      applyResponse(createEmptyTrackingRules())
    } finally {
      trackingLoading.value = false
    }
  }

  function updateImportantMetric(ruleKey: string, patch: Partial<AdminTrackingMetricRule>) {
    importantMetrics.value = importantMetrics.value.map((rule) =>
      rule.key === ruleKey ? normalizeMetricRule({ ...rule, ...patch }) : rule,
    )
  }

  function updateOptionalMetric(ruleKey: string, patch: Partial<AdminTrackingMetricRule>) {
    optionalMetrics.value = optionalMetrics.value.map((rule) =>
      rule.key === ruleKey ? normalizeMetricRule({ ...rule, ...patch }) : rule,
    )
  }

  function updateTrackingFlag(ruleKey: string, patch: Partial<AdminTrackingFlagRule>) {
    trackingFlags.value = trackingFlags.value.map((rule) =>
      rule.key === ruleKey ? normalizeFlagRule({ ...rule, ...patch }) : rule,
    )
  }

  async function saveTrackingSource() {
    sourceSaving.value = true
    trackingError.value = ''
    trackingSuccess.value = ''
    try {
      const response = await store.updateAdminTrackingSource({
        source: { ...trackingSource.value },
      })
      applyResponse(response)
      trackingSuccess.value = 'Tracking Source wurde gespeichert.'
    } catch (error) {
      trackingError.value = error instanceof Error ? error.message : 'Tracking Source konnte nicht gespeichert werden.'
    } finally {
      sourceSaving.value = false
    }
  }

  async function saveTrackingNotes() {
    notesSaving.value = true
    trackingError.value = ''
    trackingSuccess.value = ''
    try {
      const response = await store.updateAdminTrackingReviewNotes({
        manualReviewNotes: manualReviewNotes.value,
        showManualReviewNotesInReview: trackingSource.value.showManualReviewNotesInReview,
      })
      applyResponse(response)
      trackingSuccess.value = 'Manual Review Notes wurden gespeichert.'
    } catch (error) {
      trackingError.value = error instanceof Error ? error.message : 'Manual Review Notes konnten nicht gespeichert werden.'
    } finally {
      notesSaving.value = false
    }
  }

  async function saveTrackingRules() {
    rulesSaving.value = true
    trackingError.value = ''
    trackingSuccess.value = ''
    try {
      const response = await store.updateAdminTrackingRules({
        source: parseSourceSnapshot(sourceSnapshot.value),
        importantMetrics: importantMetrics.value.map(normalizeMetricRule),
        optionalMetrics: optionalMetrics.value.map(normalizeMetricRule),
        flags: trackingFlags.value.map(normalizeFlagRule),
        manualReviewNotes: notesSnapshot.value,
      })
      applyResponse(response)
      trackingSuccess.value = 'Tracking Rules wurden gespeichert.'
    } catch (error) {
      trackingError.value = error instanceof Error ? error.message : 'Tracking Rules konnten nicht gespeichert werden.'
    } finally {
      rulesSaving.value = false
    }
  }

  onMounted(loadTrackingRules)

  return {
    trackingLoading,
    rulesSaving,
    sourceSaving,
    notesSaving,
    trackingError,
    trackingSuccess,
    trackingSource,
    importantMetrics,
    optionalMetrics,
    trackingFlags,
    manualReviewNotes,
    trackingSummary,
    hasUnsavedTrackingSourceChanges,
    hasUnsavedTrackingRuleChanges,
    hasUnsavedTrackingNotesChanges,
    loadTrackingRules,
    updateImportantMetric,
    updateOptionalMetric,
    updateTrackingFlag,
    saveTrackingSource,
    saveTrackingNotes,
    saveTrackingRules,
  }
}
