<script lang="ts" setup>
import { computed, onMounted, ref, watch } from 'vue'
import { useEstimatorStore, type EstimatorPlan, type EstimatorAddOnGroup, type WorkloadEntry, type AppExample, type EstimatorCycle } from '@/stores/estimator'
import { useToastStore } from '@/stores/toast'
import BillingCycleToggle from './BillingCycleToggle.vue'
import WorkloadPicker from './WorkloadPicker.vue'
import MiniQuizDialog from './MiniQuizDialog.vue'
import RecommendedPlanCard from './RecommendedPlanCard.vue'
import AddOnsPanel from './AddOnsPanel.vue'
import EstimatorFooter from './EstimatorFooter.vue'

interface Props {
  plans: EstimatorPlan[]
  addOns: EstimatorAddOnGroup[]
  workloadMap: Record<string, WorkloadEntry>
  appExamples: AppExample[]
  accountUrl: string
}

const props = defineProps<Props>()

const store = useEstimatorStore()
const toast = useToastStore()

const quizOpen = ref<boolean>(false)
const quizReason = ref<string>('')

const cycleSuffix = computed<string>(() => {
  switch (store.cycle) {
    case 'monthly': return '/mo'
    case 'quarterly': return '/qtr'
    case 'annual': return '/yr'
  }
  return ''
})

const cycleLabel = computed<string>(() => {
  switch (store.cycle) {
    case 'monthly': return 'monthly'
    case 'quarterly': return 'quarterly (3 months)'
    case 'annual': return 'annually (12 months)'
  }
  return ''
})

const monthlyMultiplier = computed<number>(() => {
  // For "+$X/cycle" labels on add-on options. Looks up the actual cycle row,
  // but for *display* we approximate from monthly with the standard discount.
  switch (store.cycle) {
    case 'monthly': return 1
    case 'quarterly': return 3 * 0.95
    case 'annual': return 12 * 0.85
  }
  return 1
})

const currentWorkloadEntry = computed<WorkloadEntry | null>(() =>
  store.workload ? props.workloadMap[store.workload] ?? null : null,
)

function pushUrlState(): void {
  if (typeof window === 'undefined') return
  const newUrl = store.shareUrl
  // Only update if changed to avoid history thrash
  if (newUrl !== window.location.href) {
    window.history.replaceState({}, '', newUrl)
  }
}

let urlDebounce: ReturnType<typeof setTimeout> | null = null
function debouncePushUrl(): void {
  if (urlDebounce) clearTimeout(urlDebounce)
  urlDebounce = setTimeout(pushUrlState, 300)
}

function onWorkloadChange(key: string): void {
  store.setWorkload(key)
  debouncePushUrl()
}

function onPlanChange(planId: number): void {
  const previousPilot = store.managedTier === 'pilot'
  store.setPlan(planId)
  if (previousPilot && !store.pilotAvailable) {
    toast.warning('Pilot tier removed — requires VPS-8 or larger.')
  }
  debouncePushUrl()
}

function onPickPlanFromQuiz(slug: string, reason: string): void {
  const plan = props.plans.find(p => p.slug === slug)
  if (!plan) return
  store.workload = 'not_sure'
  store.setPlan(plan.id)
  quizReason.value = reason
  debouncePushUrl()
}

function onRequestUpgrade(): void {
  // Find the smallest tier-8+ plan in the catalog
  const upgrade = props.plans
    .filter(p => typeof p.features?.tier === 'number' && (p.features.tier as number) >= 8)
    .sort((a, b) => parseFloat(a.price) - parseFloat(b.price))[0]
  if (upgrade) {
    onPlanChange(upgrade.id)
    store.setManagedTier('pilot')
    toast.info(`Upgraded to ${upgrade.name} so Pilot is available.`)
  }
}

function onCycleChange(value: EstimatorCycle): void {
  store.cycle = value
  debouncePushUrl()
}

function onIpv4Change(value: number): void {
  store.ipv4Count = value
  debouncePushUrl()
}

function onManagedChange(value: 'self' | 'basic' | 'pro' | 'pilot'): void {
  store.setManagedTier(value)
  debouncePushUrl()
}

function onBackupChange(value: 'none' | 'lite' | 'standard' | 'extended' | 'vault'): void {
  store.backupTier = value
  debouncePushUrl()
}

onMounted(() => {
  store.init({
    plans: props.plans,
    addOns: props.addOns,
    workloadMap: props.workloadMap,
    appExamples: props.appExamples,
    accountUrl: props.accountUrl,
  })
  if (typeof window !== 'undefined') {
    store.hydrateFromUrl(window.location.search)
  }
})

// Auto-fallback toast on plan-driven Pilot demotion
watch(
  () => store.pilotAvailable,
  (available, prevAvailable) => {
    if (prevAvailable && !available && store.managedTier === 'pilot') {
      // store.setPlan already demoted to pro; just notify
      toast.warning('Pilot tier removed — requires VPS-8 or larger.')
    }
  },
)
</script>

<template>
  <div class="estimator-section">
    <VContainer>
      <div class="text-center mb-6">
        <VChip color="primary" variant="tonal" size="small" class="mb-2">Estimator</VChip>
        <h2 class="text-h4 font-weight-bold mb-2">Find your fit</h2>
        <p class="text-body-1 text-medium-emphasis mb-4">
          Tell us what you're running. We'll size it, price it, and let you tweak the extras.
        </p>
        <BillingCycleToggle
          :model-value="store.cycle"
          @update:model-value="onCycleChange"
        />
      </div>

      <div class="estimator-section__body">
        <WorkloadPicker
          :workload-map="workloadMap"
          :model-value="store.workload"
          @update:model-value="onWorkloadChange"
          @open-quiz="quizOpen = true"
        />

        <VExpandTransition>
          <div v-if="store.selectedPlan" class="mt-6">
            <div v-if="quizReason" class="d-flex align-center ga-2 mb-3 text-caption text-medium-emphasis">
              <VIcon icon="tabler-bulb" size="16" />
              <span>{{ quizReason }}</span>
            </div>

            <RecommendedPlanCard
              :plan="store.selectedPlan"
              :workload-entry="currentWorkloadEntry"
              :all-plans="plans"
              :cycle-price="store.planCyclePrice"
              :cycle-label="cycleLabel"
              @change-plan="onPlanChange"
            />

            <div class="mt-5">
              <AddOnsPanel
                :ipv4-count="store.ipv4Count"
                :managed-tier="store.managedTier"
                :backup-tier="store.backupTier"
                :pilot-available="store.pilotAvailable"
                :cycle-suffix="cycleSuffix"
                :monthly-multiplier="monthlyMultiplier"
                @update:ipv4-count="onIpv4Change"
                @update:managed-tier="onManagedChange"
                @update:backup-tier="onBackupChange"
                @request-upgrade="onRequestUpgrade"
              />
            </div>
          </div>
        </VExpandTransition>

        <div class="mt-6">
          <EstimatorFooter
            :cycle-total="store.cycleTotal"
            :monthly-effective="store.monthlyEffectiveTotal"
            :cycle="store.cycle"
            :checkout-url="store.checkoutUrl"
            :share-url="store.shareUrl"
            :plan-selected="store.planId !== null"
          />
        </div>
      </div>

      <MiniQuizDialog
        v-model="quizOpen"
        :app-examples="appExamples"
        :all-plans="plans"
        @pick-plan="onPickPlanFromQuiz"
      />
    </VContainer>
  </div>
</template>

<style lang="scss" scoped>
.estimator-section {
  padding: 80px 0;
  background-color: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
}

.estimator-section__body {
  max-width: 980px;
  margin: 0 auto;
}
</style>
