import { defineStore } from 'pinia'
import { computed, ref } from 'vue'

export interface DedicatedPlan {
  id: number
  slug: string
  name: string
  price: string
  setup_fee?: string | number
  features: Record<string, string | number> | null
  prices?: Array<{ billing_cycle: string; price: string }>
}

export interface DedicatedConfigValue {
  id: number
  label: string
  value: string
  monthly_price: string
  quarterly_price: string
  semi_annual_price: string
  annual_price: string
  is_default: boolean
}

export interface DedicatedConfigOption {
  id: number
  name: string
  type: string
  values: DedicatedConfigValue[]
}

export interface DedicatedConfigGroup {
  id: number
  name: string
  description: string | null
  options: DedicatedConfigOption[]
  sort_order: number
}

export type DedicatedCycle = 'monthly' | 'quarterly' | 'semi_annual' | 'annual'

export const CYCLE_MONTHS: Record<DedicatedCycle, number> = {
  monthly: 1,
  quarterly: 3,
  semi_annual: 6,
  annual: 12,
}

const CYCLES_WITH_SETUP_FEE: DedicatedCycle[] = ['monthly', 'quarterly']

export const useDedicatedConfiguratorStore = defineStore('dedicatedConfigurator', () => {
  const plan = ref<DedicatedPlan | null>(null)
  const configGroups = ref<DedicatedConfigGroup[]>([])
  const accountUrl = ref<string>('')

  // selections: groupName → option value slug (e.g., {"Dedicated 14th Gen — RAM Upgrade": "64"})
  const selections = ref<Record<string, string>>({})
  const cycle = ref<DedicatedCycle>('monthly')

  function init(catalog: {
    plan: DedicatedPlan
    configGroups: DedicatedConfigGroup[]
    accountUrl: string
  }): void {
    plan.value = catalog.plan
    configGroups.value = catalog.configGroups
    accountUrl.value = catalog.accountUrl

    // Seed selections with each group's default value (or first value if no default).
    const seeded: Record<string, string> = {}
    for (const group of catalog.configGroups) {
      const opt = group.options[0]
      if (!opt) continue
      const def = opt.values.find(v => v.is_default) ?? opt.values[0]
      if (def) seeded[group.name] = def.value
    }
    selections.value = seeded
  }

  function setSelection(groupName: string, value: string): void {
    selections.value = { ...selections.value, [groupName]: value }
  }

  function findGroup(groupName: string): DedicatedConfigGroup | null {
    return configGroups.value.find(g => g.name === groupName) ?? null
  }

  function findValue(groupName: string, valueSlug: string): DedicatedConfigValue | null {
    const g = findGroup(groupName)
    if (!g || !g.options[0]) return null
    return g.options[0].values.find(v => v.value === valueSlug) ?? null
  }

  function pickCyclePrice(value: DedicatedConfigValue, c: DedicatedCycle): number {
    const raw = c === 'monthly'
      ? value.monthly_price
      : c === 'quarterly'
        ? value.quarterly_price
        : c === 'semi_annual'
          ? value.semi_annual_price
          : value.annual_price
    return raw ? parseFloat(raw) : 0
  }

  function planPriceForCycle(c: DedicatedCycle): number {
    if (!plan.value) return 0
    if (plan.value.prices && plan.value.prices.length > 0) {
      const pp = plan.value.prices.find(p => p.billing_cycle === c)
      if (pp) return parseFloat(pp.price)
    }
    return parseFloat(plan.value.price) * CYCLE_MONTHS[c]
  }

  const baselinePrice = computed<number>(() => planPriceForCycle(cycle.value))

  const addOnsTotal = computed<number>(() => {
    let total = 0
    for (const [groupName, valueSlug] of Object.entries(selections.value)) {
      const v = findValue(groupName, valueSlug)
      if (v) total += pickCyclePrice(v, cycle.value)
    }
    return total
  })

  const setupFee = computed<number>(() => {
    if (!plan.value) return 0
    const fee = parseFloat(String(plan.value.setup_fee ?? 0))
    if (fee <= 0) return 0
    return CYCLES_WITH_SETUP_FEE.includes(cycle.value) ? fee : 0
  })

  const cycleSubtotal = computed<number>(() => baselinePrice.value + addOnsTotal.value)

  const cycleTotal = computed<number>(() => cycleSubtotal.value + setupFee.value)

  const monthlyEffective = computed<number>(() => cycleSubtotal.value / CYCLE_MONTHS[cycle.value])

  const isSetupFeeWaived = computed<boolean>(() => {
    if (!plan.value) return true
    const fee = parseFloat(String(plan.value.setup_fee ?? 0))
    if (fee <= 0) return true
    return !CYCLES_WITH_SETUP_FEE.includes(cycle.value)
  })

  // Build the share URL with all current selections + cycle as query params.
  // Param keys are short and readable so URLs stay shareable.
  const shareUrl = computed<string>(() => {
    if (!plan.value) return ''
    const params = new URLSearchParams()
    if (cycle.value !== 'monthly') params.set('cycle', cycle.value)
    for (const [groupName, valueSlug] of Object.entries(selections.value)) {
      const param = groupNameToParam(groupName)
      if (!param) continue
      const g = findGroup(groupName)
      const def = g?.options[0]?.values.find(v => v.is_default)?.value
      // Only add to URL if non-default
      if (def && valueSlug === def) continue
      params.set(param, valueSlug)
    }
    const qs = params.toString()
    if (typeof window === 'undefined') return qs ? `/dedicated-servers/${plan.value.slug}?${qs}` : `/dedicated-servers/${plan.value.slug}`
    return qs ? `${window.location.origin}${window.location.pathname}?${qs}` : `${window.location.origin}${window.location.pathname}`
  })

  const checkoutUrl = computed<string>(() => {
    if (!plan.value) return ''
    const params = new URLSearchParams()
    if (cycle.value !== 'monthly') params.set('cycle', cycle.value)
    for (const [groupName, valueSlug] of Object.entries(selections.value)) {
      const param = groupNameToParam(groupName)
      if (!param) continue
      const g = findGroup(groupName)
      const def = g?.options[0]?.values.find(v => v.is_default)?.value
      if (def && valueSlug === def) continue
      params.set(param, valueSlug)
    }
    const qs = params.toString()
    const base = `${accountUrl.value}/checkout/${plan.value.id}`
    return qs ? `${base}?${qs}` : base
  })

  function groupNameToParam(groupName: string): string | null {
    const map: Record<string, string> = {
      'Dedicated 14th Gen — CPU Upgrade': 'cpu',
      'Dedicated 14th Gen — CPU Upgrade (R740xd)': 'cpu',
      'Dedicated 14th Gen — RAM Upgrade': 'ram',
      'Dedicated 14th Gen — Operating System': 'os',
      'Dedicated 14th Gen — Bandwidth': 'bw',
      'Dedicated 14th Gen — IPv4 Block': 'ipv4',
    }
    return map[groupName] ?? null
  }

  function paramToGroupName(param: string): string[] {
    // Returns matching group names for a query param. Some params (cpu) map to
    // multiple groups depending on chassis (CPU vs CPU R740xd) — we set on
    // every matching group, the visible one (only one is attached) wins.
    const map: Record<string, string[]> = {
      cpu: ['Dedicated 14th Gen — CPU Upgrade', 'Dedicated 14th Gen — CPU Upgrade (R740xd)'],
      ram: ['Dedicated 14th Gen — RAM Upgrade'],
      os: ['Dedicated 14th Gen — Operating System'],
      bw: ['Dedicated 14th Gen — Bandwidth'],
      ipv4: ['Dedicated 14th Gen — IPv4 Block'],
    }
    return map[param] ?? []
  }

  function hydrateFromUrl(search: string): void {
    const p = new URLSearchParams(search)

    const c = p.get('cycle')
    if (c && (['monthly', 'quarterly', 'semi_annual', 'annual'] as const).includes(c as DedicatedCycle)) {
      cycle.value = c as DedicatedCycle
    }

    for (const param of ['cpu', 'ram', 'os', 'bw', 'ipv4']) {
      const v = p.get(param)
      if (!v) continue
      for (const groupName of paramToGroupName(param)) {
        const group = findGroup(groupName)
        if (!group) continue
        const validValue = group.options[0]?.values.find(val => val.value === v)
        if (validValue) {
          selections.value[groupName] = v
        }
      }
    }
  }

  return {
    plan,
    configGroups,
    accountUrl,
    selections,
    cycle,
    baselinePrice,
    addOnsTotal,
    setupFee,
    cycleSubtotal,
    cycleTotal,
    monthlyEffective,
    isSetupFeeWaived,
    shareUrl,
    checkoutUrl,
    init,
    setSelection,
    hydrateFromUrl,
    findGroup,
    findValue,
    pickCyclePrice,
  }
})
