<script setup lang="ts">
import { ref, shallowRef, computed, watch } from 'vue'
import { useIntegrationStore } from '@KTXC/stores/integrationStore'
import { useServicesStore } from '@MailManager/stores/servicesStore'
import { useProvidersStore } from '@MailManager/stores/providersStore'
import { ServiceObject, type ProviderObject } from '@MailManager/models'
import type { ProviderDiscoveryStatus, ServiceAddressInterface, ServiceInterface, ServiceLocation } from '@MailManager/types'
import DiscoveryEntryPanel from '@MailManager/components/steps/DiscoveryEntryPanel.vue'
import DiscoveryStatusPanel from '@MailManager/components/steps/DiscoveryStatusPanel.vue'
import ProviderSelectionPanel from '@MailManager/components/steps/ProviderSelectionPanel.vue'
import ProviderProtocolPanel from '@MailManager/components/steps/ProviderProtocolPanel.vue'
import ProviderAuthPanel from '@MailManager/components/steps/ProviderAuthPanel.vue'
import TestAndSavePanel from '@MailManager/components/steps/TestAndSavePanel.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 integrationStore = useIntegrationStore()
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)

// Address entered during discovery, as a service address object
const discoverServiceAddress = computed<ServiceAddressInterface | null>(() =>
  discoverAddress.value ? { address: discoverAddress.value } : null
)

// Step 2: Discovery Status / Provider Selection
const selectedProvider = shallowRef<ProviderObject | null>(null)
const selectedService = shallowRef<ServiceObject | null>(null)

// Step 5: Test & Save
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 !!selectedService.value?.location
    }
    if (currentStep.value === MANUAL_STEPS.AUTH) {
      return !!selectedService.value?.identity
    }
  } else {
    if (currentStep.value === DISCOVERY_STEPS.AUTH) {
      return !!selectedService.value?.identity
    }
  }
  return false
})

function createServiceObject(
  providerId: string,
  data: Partial<ServiceInterface> = {}
): ServiceObject {
  const model: ServiceInterface = {
    '@type': 'mail:service',
    version: 1,
    provider: providerId,
    identifier: null,
    label: data.label ?? null,
    enabled: data.enabled ?? true,
    primaryAddress: data.primaryAddress ?? discoverServiceAddress.value,
    secondaryAddresses: data.secondaryAddresses ?? null,
    location: data.location ?? null,
    identity: data.identity ?? null,
    capabilities: data.capabilities ?? {},
    auxiliary: data.auxiliary ?? {}
  }

  const factoryItem = integrationStore.getItemById('mail_provider_factory_service', providerId) as any
  const factory = factoryItem?.factory
  return factory ? factory(model) : new ServiceObject().fromJson(model)
}

function setSelectedProviderAndService(providerId: string, service: ServiceObject) {
  selectedProvider.value = providersStore.provider(providerId)
  selectedService.value = service
  testAndSaveValid.value = false
}

function handleServiceUpdate(service: ServiceObject) {
  selectedService.value = service
  testAndSaveValid.value = false
}

function handleServiceTested(success: boolean) {
  testAndSaveValid.value = success
}

// 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
  isManualMode.value = false
  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 discovered = discoveredServices.value.find(s => s.provider === identifier)
  if (!discovered || !discovered.location) return

  const discoveredJson = discovered.toJson()
  const service = createServiceObject(identifier, {
    ...discoveredJson,
    label: discoveredJson.label || discoverAddress.value,
    enabled: discoveredJson.enabled ?? true,
    primaryAddress: discoveredJson.primaryAddress ?? discoverServiceAddress.value,
    location: discoveredJson.location
  })
  setSelectedProviderAndService(identifier, service)
  
  // 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
  const discovered = discoveredServices.value.find(s => s.provider === identifier)
  const discoveredJson = discovered?.toJson()
  const service = createServiceObject(identifier, {
    ...discoveredJson,
    label: discoveredJson?.label || discoverAddress.value,
    enabled: discoveredJson?.enabled ?? true,
    primaryAddress: discoveredJson?.primaryAddress ?? discoverServiceAddress.value,
    location: discoveredJson?.location ?? null
  })

  setSelectedProviderAndService(identifier, service)
  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
  const service = createServiceObject(identifier, {
    label: discoverAddress.value,
    enabled: true,
    primaryAddress: discoverServiceAddress.value,
    location: null,
    identity: null
  })

  setSelectedProviderAndService(identifier, service)
  currentStep.value = MANUAL_STEPS.CONFIG  // Go to manual config
}

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

async function testConnection() {
  if (!selectedProvider.value || !selectedService.value) {
    return {
      success: false,
      message: 'Missing configuration'
    }
  }

  if (!selectedService.value.location || !selectedService.value.identity) {
    return {
      success: false,
      message: 'Missing configuration'
    }
  }
  
  const testResult = await servicesStore.test(
    selectedProvider.value.identifier,
    null,
    selectedService.value.location,
    selectedService.value.identity
  )

  return testResult
}

async function saveAccount() {
  if (!selectedProvider.value || !selectedService.value) return

  const serviceData = selectedService.value.toJson()
  if (!serviceData.location || !serviceData.identity) return
  
  saving.value = true

  try {
    const accountData = {
      label: serviceData.label || discoverAddress.value,
      primaryAddress: serviceData.primaryAddress ?? discoverServiceAddress.value,
      enabled: serviceData.enabled,
      location: serviceData.location,
      identity: serviceData.identity,
      auxiliary: serviceData.auxiliary
    }

    await servicesStore.create(
      selectedProvider.value.identifier,
      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
  selectedProvider.value = null
  selectedService.value = null
  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">
              <DiscoveryEntryPanel
                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 -->
              <DiscoveryStatusPanel
                v-if="!isManualMode"
                :address="discoverAddress"
                :status="discoveryStatus"
                @select="handleProviderSelect"
                @advanced="handleProviderAdvanced"
                @manual="handleManualMode"
                @back="goBackToIdentity"
              />
              
              <!-- Manual path - provider picker -->
              <ProviderSelectionPanel
                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 -->
              <ProviderProtocolPanel
                v-if="isManualMode && selectedProvider && selectedService"
                :provider="selectedProvider"
                :service="selectedService"
                @update:service="handleServiceUpdate"
              />
              
              <ProviderAuthPanel
                v-else-if="!isManualMode && selectedProvider && selectedService"
                :provider="selectedProvider"
                :service="selectedService"
                @update:service="handleServiceUpdate"
              />
            </v-card>
          </template>

          <!-- Step 4: Auth (manual) OR Test (discovery) -->
          <template #item.4>
            <v-card flat class="pa-6">
              <ProviderAuthPanel
                v-if="isManualMode && selectedProvider && selectedService"
                :provider="selectedProvider"
                :service="selectedService"
                @update:service="handleServiceUpdate"
              />
              
              <!-- Discovery path: Test & Save -->
              <TestAndSavePanel
                v-else-if="!isManualMode && selectedProvider && selectedService"
                :provider="selectedProvider"
                :service="selectedService"
                :on-test="testConnection"
                @update:service="handleServiceUpdate"
                @tested="handleServiceTested"
              />
            </v-card>
          </template>

          <!-- Step 5: Test & Save (manual only) -->
          <template #item.5>
            <v-card flat class="pa-6">
              <TestAndSavePanel
                v-if="selectedProvider && selectedService"
                :provider="selectedProvider"
                :service="selectedService"
                :on-test="testConnection"
                @update:service="handleServiceUpdate"
                @tested="handleServiceTested"
              />
            </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>