<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useServicesStore } from '@MailManager/stores/servicesStore'
import { useProvidersStore } from '@MailManager/stores/providersStore'
import type { ProviderDiscoveryStatus, ServiceLocation, ServiceIdentity } from '@MailManager/types'
import type { ServiceObject } from '@MailManager/models/service'
import DiscoveryStatusStep from '@MailManager/components/steps/DiscoveryStatusStep.vue'
import ProviderSelectionStep from '@MailManager/components/steps/ProviderSelectionStep.vue'
import ProviderConfigStep from '@MailManager/components/steps/ProviderConfigStep.vue'
import ProviderAuthStep from '@MailManager/components/steps/ProviderAuthStep.vue'
import TestAndSaveStep from '@MailManager/components/steps/TestAndSaveStep.vue'
import DiscoveryEntryStep from '@MailManager/components/steps/DiscoveryEntryStep.vue'

// ==================== Step Constants ====================
// Discovery flow: Entry → Discovery → Auth → Test
const DISCOVERY_STEPS = {
  ENTRY: 1,
  DISCOVERY: 2,
  AUTH: 3,
  TEST: 4
} as const

// Manual flow: Entry → Provider Select → Config → Auth → Test
const MANUAL_STEPS = {
  ENTRY: 1,
  PROVIDER_SELECT: 2,
  CONFIG: 3,
  AUTH: 4,
  TEST: 5
} as const

const props = defineProps<{
  modelValue: boolean
}>()

const emit = defineEmits<{
  'update:modelValue': [value: boolean]
  'saved': []
}>()

const servicesStore = useServicesStore()
const providersStore = useProvidersStore()

const dialogOpen = computed({
  get: () => props.modelValue,
  set: (val) => emit('update:modelValue', val)
})

const currentStep = ref<number>(DISCOVERY_STEPS.ENTRY)
const saving = ref(false)
const isManualMode = ref(false)

// Step 1: Entry
const discoverAddress = ref<string>('')
const discoverSecret = ref<string | null>(null)
const discoverHostname = ref<string | null>(null)

// Step 2: Discovery Status / Provider Selection
const selectedProviderId = ref<string | undefined>(undefined)
const selectedProviderLabel = ref<string>('')

// Step 3: Config (manual only) OR Auth (both paths)
const configuredLocation = ref<ServiceLocation | null>(null)

// Step 4: Auth (both paths)
const configuredIdentity = ref<ServiceIdentity | null>(null)
const authValid = ref(false)

// Step 5: Test & Save
const accountLabel = ref<string>('')
const accountEnabled = ref(true)
const testAndSaveValid = ref(false)

// Local discovery state (not stored in global store)
const discoveredServices = ref<ServiceObject[]>([])
const discoveryStatus = ref<Record<string, ProviderDiscoveryStatus>>({})

// Load providers when dialog opens
watch(dialogOpen, async (isOpen) => {
  if (isOpen && !providersStore.has) {
    await providersStore.list()
  }
})

// Stepper configuration
const stepperItems = computed(() => {
  if (isManualMode.value) {
    // Manual: Entry → Selection → Config → Auth → Test
    return [
      { title: 'Email', value: MANUAL_STEPS.ENTRY },
      { title: 'Provider', value: MANUAL_STEPS.PROVIDER_SELECT },
      { title: 'Protocol', value: MANUAL_STEPS.CONFIG },
      { title: 'Authentication', value: MANUAL_STEPS.AUTH },
      { title: 'Test & Save', value: MANUAL_STEPS.TEST }
    ]
  }
  
  // Discovery: Entry → Discovery → Auth → Test
  if (currentStep.value >= DISCOVERY_STEPS.AUTH) {
    return [
      { title: 'Email', value: DISCOVERY_STEPS.ENTRY },
      { title: 'Discovery', value: DISCOVERY_STEPS.DISCOVERY },
      { title: 'Authentication', value: DISCOVERY_STEPS.AUTH },
      { title: 'Test & Save', value: DISCOVERY_STEPS.TEST }
    ]
  }
  
  return [
    { title: 'Email', value: DISCOVERY_STEPS.ENTRY },
    { title: 'Discovery', value: DISCOVERY_STEPS.DISCOVERY }
  ]
})

const canSave = computed(() => {
  return testAndSaveValid.value
})

// Navigation button visibility
const showNextButton = computed(() => {
  if (isManualMode.value) {
    // Manual: Show Next on Config (3) and Auth (4)
    return currentStep.value === MANUAL_STEPS.CONFIG || currentStep.value === MANUAL_STEPS.AUTH
  } else {
    // Discovery: Show Next on Auth (3)
    return currentStep.value === DISCOVERY_STEPS.AUTH
  }
})

const showSaveButton = computed(() => {
  if (isManualMode.value) {
    return currentStep.value === MANUAL_STEPS.TEST
  } else {
    return currentStep.value === DISCOVERY_STEPS.TEST
  }
})

const canProceedToNext = computed(() => {
  if (isManualMode.value) {
    if (currentStep.value === MANUAL_STEPS.CONFIG) {
      return !!configuredLocation.value
    }
    if (currentStep.value === MANUAL_STEPS.AUTH) {
      return authValid.value
    }
  } else {
    if (currentStep.value === DISCOVERY_STEPS.AUTH) {
      return authValid.value
    }
  }
  return false
})

// Navigation methods
function handlePreviousStep() {
  if (currentStep.value > 1) {
    currentStep.value--
  }
}

function handleNextStep() {
  if (isManualMode.value) {
    if (currentStep.value < MANUAL_STEPS.TEST) {
      currentStep.value++
    }
  } else {
    if (currentStep.value < DISCOVERY_STEPS.TEST) {
      currentStep.value++
    }
  }
}

async function handleDiscover() {
  // Move to discovery status screen
  currentStep.value = DISCOVERY_STEPS.DISCOVERY
  
  // Extract provider IDs
  const providerIds = Object.values(providersStore.providers).map(p => p.identifier)
  
  if (providerIds.length === 0) {
    console.error('No providers available')
    return
  }
  
  // Initialize status for all providers
  discoveryStatus.value = providerIds.reduce((acc, identifier) => {
    acc[identifier] = {
      provider: identifier,
      status: 'pending'
    }
    return acc
  }, {} as Record<string, ProviderDiscoveryStatus>)
  
  discoveredServices.value = []
  
  // Start discovery for each provider in parallel
  const promises = providerIds.map(async (identifier) => {
    // Mark as discovering
    discoveryStatus.value[identifier].status = 'discovering'
    
    try {
      let discoveredService: any = undefined
      await servicesStore.discover(
        discoverAddress.value,
        discoverSecret.value || undefined,
        discoverHostname.value || undefined,
        identifier,
        (service) => { discoveredService = service }
      )
      
      // Success - check if we got results for this provider
      if (discoveredService && discoveredService.location) {
        discoveryStatus.value[identifier] = {
          provider: identifier,
          status: 'success',
          location: discoveredService.location,
          metadata: extractLocationMetadata(discoveredService.location)
        }
        discoveredServices.value.push(discoveredService)
      } else {
        // No configuration found for this provider
        discoveryStatus.value[identifier].status = 'failed'
        discoveryStatus.value[identifier].error = 'Not configured'
      }
    } catch (error: any) {
      // Failed - update status with error
      discoveryStatus.value[identifier] = {
        provider: identifier,
        status: 'failed',
        error: error.message || 'Discovery failed'
      }
    }
  })
  
  // Wait for all discoveries to complete
  await Promise.allSettled(promises)
}

/**
 * Extract display metadata from location for UI
 */
function extractLocationMetadata(location: ServiceLocation) {
  switch (location.type) {
    case 'URI':
      return {
        host: location.host,
        port: location.port,
        protocol: location.scheme
      }
    case 'SOCKET_SOLE':
      return {
        host: location.host,
        port: location.port,
        protocol: location.encryption
      }
    default:
      return {}
  }
}

async function handleProviderSelect(identifier: string) {
  // User clicked "Select" on discovered provider - skip config, go to auth
  const service = discoveredServices.value.find(s => s.provider === identifier)
  if (!service || !service.location) return
  
  selectedProviderId.value = identifier
  selectedProviderLabel.value = providersStore.provider(identifier)?.label || identifier
  configuredLocation.value = service.location
  
  // Discovery path: Entry → Discovery → Auth → Test
  currentStep.value = DISCOVERY_STEPS.AUTH  // Go to auth step
}

function handleProviderAdvanced(identifier: string) {
  // User clicked "Advanced" - show manual config with pre-filled values
  selectedProviderId.value = identifier
  selectedProviderLabel.value = providersStore.provider(identifier)?.label || identifier
  const service = discoveredServices.value.find(s => s.provider === identifier)
  
  configuredLocation.value = service?.location || null
  isManualMode.value = true
  
  // Manual path: Entry → Discovery → Config → Auth → Test
  currentStep.value = MANUAL_STEPS.CONFIG  // Go to config step
}

function handleManualMode() {
  // User clicked "Manual Configuration" - show provider picker
  isManualMode.value = true
  discoveredServices.value = []
  discoveryStatus.value = {}
  currentStep.value = MANUAL_STEPS.PROVIDER_SELECT  // Go to provider selection
}

function handleProviderManualSelect(identifier: string) {
  // User selected a provider in manual mode
  selectedProviderId.value = identifier
  selectedProviderLabel.value = providersStore.provider(identifier)?.label || identifier
  currentStep.value = MANUAL_STEPS.CONFIG  // Go to manual config
}

function goBackToIdentity() {
  currentStep.value = DISCOVERY_STEPS.ENTRY
  isManualMode.value = false
  discoveredServices.value = []
  discoveryStatus.value = {}
}

async function testConnection() {
  if (!selectedProviderId.value || !configuredLocation.value || !configuredIdentity.value) {
    return {
      success: false,
      message: 'Missing configuration'
    }
  }
  
  const testResult = await servicesStore.test(
    selectedProviderId.value,
    null,
    configuredLocation.value,
    configuredIdentity.value
  )

  return testResult
}

async function saveAccount() {
  if (!selectedProviderId.value || !configuredLocation.value || !configuredIdentity.value) return
  
  saving.value = true

  try {
    const accountData = {
      label: accountLabel.value || discoverAddress.value,
      email: discoverAddress.value,
      enabled: accountEnabled.value,
      location: configuredLocation.value,
      identity: configuredIdentity.value
    }

    await servicesStore.create(
      selectedProviderId.value,
      accountData
    )

    emit('saved')
    close()
  } catch (error) {
    console.error('Failed to save account:', error)
    // TODO: Show error message to user
  } finally {
    saving.value = false
  }
}

function close() {
  dialogOpen.value = false
  // Reset state after animation
  setTimeout(resetForm, 300)
}

function resetForm() {
  currentStep.value = DISCOVERY_STEPS.ENTRY
  isManualMode.value = false
  discoverAddress.value = ''
  discoverSecret.value = null
  discoverHostname.value = null
  selectedProviderId.value = undefined
  selectedProviderLabel.value = ''
  configuredLocation.value = null
  configuredIdentity.value = null
  authValid.value = false
  accountLabel.value = ''
  accountEnabled.value = true
  testAndSaveValid.value = false
  discoveredServices.value = []
  discoveryStatus.value = {}
}
</script>

<template>
  <v-dialog
    v-model="dialogOpen"
    max-width="900"
    persistent
    scrollable
  >
    <v-card>
      <v-card-title class="d-flex justify-space-between align-center pa-6">
        <span class="text-h5">Add Mail Account</span>
        <v-btn
          icon="mdi-close"
          variant="text"
          @click="close"
        />
      </v-card-title>

      <v-divider />

      <v-card-text class="pa-0">
        <v-stepper
          v-model="currentStep"
          :items="stepperItems"
          alt-labels
          flat
          hide-actions
        >
          <!-- Step 1: Discovery Entry -->
          <template #item.1>
            <v-card flat class="pa-6">
              <DiscoveryEntryStep
                v-model:address="discoverAddress"
                v-model:secret="discoverSecret"
                v-model:hostname="discoverHostname"
                @discover="handleDiscover"
                @manual="handleManualMode"
              />
            </v-card>
          </template>

          <!-- Step 2: Discovery Status OR Provider Selection -->
          <template #item.2>
            <v-card flat class="pa-6">
              <!-- Discovery path -->
              <DiscoveryStatusStep
                v-if="!isManualMode"
                :address="discoverAddress"
                :status="discoveryStatus"
                @select="handleProviderSelect"
                @advanced="handleProviderAdvanced"
                @manual="handleManualMode"
                @back="goBackToIdentity"
              />
              
              <!-- Manual path - provider picker -->
              <ProviderSelectionStep
                v-else
                @select="handleProviderManualSelect"
                @back="goBackToIdentity"
              />
            </v-card>
          </template>

          <!-- Step 3: Config (manual) OR Auth (discovery) -->
          <template #item.3>
            <v-card flat class="pa-6">
              <!-- Manual path: Protocol Configuration -->
              <ProviderConfigStep
                v-if="isManualMode && selectedProviderId"
                :provider-id="selectedProviderId"
                :discovered-location="configuredLocation || undefined"
                v-model="configuredLocation"
                @valid="() => { /* Can proceed to next step */ }"
              />
              
              <ProviderAuthStep
                v-else-if="!isManualMode && selectedProviderId"
                :provider-id="selectedProviderId"
                :provider-label="selectedProviderLabel"
                :email-address="discoverAddress"
                :discovered-location="configuredLocation || undefined"
                :prefilled-identity="discoverAddress"
                :prefilled-secret="discoverSecret || undefined"
                v-model="configuredIdentity"
                @valid="(valid) => authValid = valid"
              />
            </v-card>
          </template>

          <!-- Step 4: Auth (manual) OR Test (discovery) -->
          <template #item.4>
            <v-card flat class="pa-6">
              <ProviderAuthStep
                v-if="isManualMode && selectedProviderId"
                :provider-id="selectedProviderId"
                :provider-label="selectedProviderLabel"
                :email-address="discoverAddress"
                :discovered-location="configuredLocation || undefined"
                :prefilled-identity="discoverAddress"
                :prefilled-secret="discoverSecret || undefined"
                v-model="configuredIdentity"
                @valid="(valid) => authValid = valid"
              />
              
              <!-- Discovery path: Test & Save -->
              <TestAndSaveStep
                v-else-if="!isManualMode && selectedProviderId"
                :provider-id="selectedProviderId"
                :provider-label="selectedProviderLabel"
                :email-address="discoverAddress"
                :location="configuredLocation"
                :identity="configuredIdentity"
                :prefilled-label="discoverAddress"
                :on-test="testConnection"
                @update:label="(val) => accountLabel = val"
                @update:enabled="(val) => accountEnabled = val"
                @valid="(valid) => testAndSaveValid = valid"
              />
            </v-card>
          </template>

          <!-- Step 5: Test & Save (manual only) -->
          <template #item.5>
            <v-card flat class="pa-6">
              <TestAndSaveStep
                v-if="selectedProviderId"
                :provider-id="selectedProviderId"
                :provider-label="selectedProviderLabel"
                :email-address="discoverAddress"
                :location="configuredLocation"
                :identity="configuredIdentity"
                :prefilled-label="discoverAddress"
                :on-test="testConnection"
                @update:label="(val) => accountLabel = val"
                @update:enabled="(val) => accountEnabled = val"
                @valid="(valid) => testAndSaveValid = valid"
              />
            </v-card>
          </template>
        </v-stepper>
      </v-card-text>

      <v-divider />

      <v-card-actions class="pa-6">
        <!-- Previous Button -->
        <v-btn
          v-if="currentStep > 1"
          variant="text"
          prepend-icon="mdi-arrow-left"
          @click="handlePreviousStep"
        >
          Previous
        </v-btn>
        
        <v-spacer />
        
        <v-btn
          variant="text"
          @click="close"
        >
          Cancel
        </v-btn>
        
        <!-- Next Button -->
        <v-btn
          v-if="showNextButton"
          color="primary"
          append-icon="mdi-arrow-right"
          :disabled="!canProceedToNext"
          @click="handleNextStep"
        >
          Next
        </v-btn>
        
        <!-- Save Button -->
        <v-btn
          v-if="showSaveButton"
          color="primary"
          :loading="saving"
          :disabled="!canSave"
          @click="saveAccount"
        >
          <v-icon start>mdi-content-save</v-icon>
          Save Account
        </v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>