<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { LocationSocketSplit } from '@KTXM/MailManager/models/location'
import { ServiceObject } from '@KTXM/MailManager/models/service'
import type {
  ServiceLocation,
  ServiceLocationSocketSplit,
} from '@KTXM/MailManager/types/service'
import type {
  ProviderProtocolPanelProps,
  ProviderProtocolPanelEmits,
} from '@KTXM/MailManager/types/integration'

type Encryption = 'none' | 'ssl' | 'tls' | 'starttls'

const props = defineProps<ProviderProtocolPanelProps>()
const emit = defineEmits<ProviderProtocolPanelEmits>()

// ── Inbound (IMAP) ──────────────────────────────────────────────────────────
const inboundHost = ref('')
const inboundEncryption = ref<Encryption>('ssl')
const inboundPort = ref('993')
const inboundVerifyPeer = ref(true)
const inboundVerifyHost = ref(true)

// ── Outbound (SMTP) ─────────────────────────────────────────────────────────
const outboundHost = ref('')
const outboundEncryption = ref<Encryption>('starttls')
const outboundPort = ref('587')
const outboundVerifyPeer = ref(true)
const outboundVerifyHost = ref(true)

const encryptionOptions = [
  { title: 'Implicit TLS (SSL)', value: 'ssl' },
  { title: 'TLS', value: 'tls' },
  { title: 'STARTTLS', value: 'starttls' },
  { title: 'None', value: 'none' },
]

const rules = {
  required: (value: unknown) => !!value || 'This field is required',
  port: (value: string) => {
    const numericValue = Number(value)
    return Number.isInteger(numericValue) && numericValue >= 1 && numericValue <= 65535
      ? true
      : 'Port must be between 1 and 65535'
  },
}

const inboundValid = computed(() => !!inboundHost.value && rules.port(inboundPort.value) === true)
const outboundValid = computed(() => !!outboundHost.value && rules.port(outboundPort.value) === true)
const isValid = computed(() => inboundValid.value && outboundValid.value)

const currentLocation = computed((): ServiceLocationSocketSplit | null => {
  if (!isValid.value) {
    return null
  }

  return {
    type: 'SOCKET_SPLIT',
    inboundHost: inboundHost.value,
    inboundPort: Number(inboundPort.value),
    inboundEncryption: inboundEncryption.value,
    inboundVerifyPeer: inboundVerifyPeer.value,
    inboundVerifyHost: inboundVerifyHost.value,
    outboundHost: outboundHost.value,
    outboundPort: Number(outboundPort.value),
    outboundEncryption: outboundEncryption.value,
    outboundVerifyPeer: outboundVerifyPeer.value,
    outboundVerifyHost: outboundVerifyHost.value,
  }
})

watch(
  () => [props.service, props.discoveredLocation] as const,
  ([service, discoveredLocation]) => {
    syncFromLocation(service?.location?.toJson() ?? discoveredLocation ?? null)
  },
  { immediate: true }
)

watch(
  currentLocation,
  location => {
    const existingLocation = props.service?.location?.toJson() ?? null
    if (sameLocation(existingLocation, location)) {
      return
    }

    const nextService = props.service ?? new ServiceObject()

    if (location === null) {
      nextService.location = null
      emit('update:service', nextService)
      return
    }

    if (nextService.location instanceof LocationSocketSplit) {
      const target = nextService.location
      target.inboundHost = location.inboundHost
      target.inboundPort = location.inboundPort
      target.inboundEncryption = location.inboundEncryption
      target.inboundVerifyPeer = location.inboundVerifyPeer ?? true
      target.inboundVerifyHost = location.inboundVerifyHost ?? true
      target.outboundHost = location.outboundHost
      target.outboundPort = location.outboundPort
      target.outboundEncryption = location.outboundEncryption
      target.outboundVerifyPeer = location.outboundVerifyPeer ?? true
      target.outboundVerifyHost = location.outboundVerifyHost ?? true
    } else {
      nextService.location = LocationSocketSplit.fromJson(location)
    }

    emit('update:service', nextService)
  },
  { immediate: true, deep: true }
)

watch(inboundEncryption, (next, previous) => {
  const previousDefault = defaultInboundPort(previous)
  if (!inboundPort.value || Number(inboundPort.value) === previousDefault) {
    inboundPort.value = String(defaultInboundPort(next))
  }
})

watch(outboundEncryption, (next, previous) => {
  const previousDefault = defaultOutboundPort(previous)
  if (!outboundPort.value || Number(outboundPort.value) === previousDefault) {
    outboundPort.value = String(defaultOutboundPort(next))
  }
})

function syncFromLocation(location: ServiceLocation | null) {
  const split = location?.type === 'SOCKET_SPLIT' ? location : null

  inboundHost.value = split?.inboundHost ?? ''
  inboundEncryption.value = split?.inboundEncryption ?? 'ssl'
  inboundPort.value = String(split?.inboundPort ?? defaultInboundPort(inboundEncryption.value))
  inboundVerifyPeer.value = split?.inboundVerifyPeer ?? true
  inboundVerifyHost.value = split?.inboundVerifyHost ?? true

  outboundHost.value = split?.outboundHost ?? ''
  outboundEncryption.value = split?.outboundEncryption ?? 'starttls'
  outboundPort.value = String(split?.outboundPort ?? defaultOutboundPort(outboundEncryption.value))
  outboundVerifyPeer.value = split?.outboundVerifyPeer ?? true
  outboundVerifyHost.value = split?.outboundVerifyHost ?? true
}

function sameLocation(a: ServiceLocation | null, b: ServiceLocation | null): boolean {
  if (a === null || b === null) {
    return a === b
  }

  if (a.type !== 'SOCKET_SPLIT' || b.type !== 'SOCKET_SPLIT') {
    return false
  }

  return a.inboundHost === b.inboundHost
    && a.inboundPort === b.inboundPort
    && a.inboundEncryption === b.inboundEncryption
    && (a.inboundVerifyPeer ?? true) === (b.inboundVerifyPeer ?? true)
    && (a.inboundVerifyHost ?? true) === (b.inboundVerifyHost ?? true)
    && a.outboundHost === b.outboundHost
    && a.outboundPort === b.outboundPort
    && a.outboundEncryption === b.outboundEncryption
    && (a.outboundVerifyPeer ?? true) === (b.outboundVerifyPeer ?? true)
    && (a.outboundVerifyHost ?? true) === (b.outboundVerifyHost ?? true)
}

function defaultInboundPort(encryption: Encryption): number {
  return encryption === 'ssl' || encryption === 'tls' ? 993 : 143
}

function defaultOutboundPort(encryption: Encryption): number {
  if (encryption === 'ssl') {
    return 465
  }
  if (encryption === 'none') {
    return 25
  }
  return 587
}
</script>

<template>
  <div class="imap-protocol-panel">
    <h3 class="text-h6 mb-4">Connection Settings</h3>
    <p class="text-body-2 mb-6">Configure the incoming (IMAP) and outgoing (SMTP) servers, transport security, and certificate verification for this mailbox.</p>

    <!-- ── Incoming (IMAP) ─────────────────────────────────────────────────── -->
    <div class="d-flex align-center mb-4">
      <v-icon start color="primary">mdi-email-arrow-left</v-icon>
      <span class="text-subtitle-1 font-weight-medium">Incoming mail (IMAP)</span>
    </div>

    <v-text-field
      v-model="inboundHost"
      label="IMAP Server Host"
      hint="For example: imap.example.com"
      persistent-hint
      variant="outlined"
      prepend-inner-icon="mdi-server"
      class="mb-4"
      autocomplete="off"
      autocorrect="off"
      autocapitalize="none"
      :rules="[rules.required]"
    />

    <v-select
      v-model="inboundEncryption"
      :items="encryptionOptions"
      label="Security"
      variant="outlined"
      prepend-inner-icon="mdi-shield-lock"
      class="mb-4"
    />

    <v-text-field
      v-model="inboundPort"
      label="Port"
      hint="Defaults to 993 for TLS/SSL and 143 for plain or STARTTLS"
      persistent-hint
      variant="outlined"
      prepend-inner-icon="mdi-numeric"
      class="mb-4"
      type="number"
      min="1"
      max="65535"
      :rules="[rules.required, rules.port]"
    />

    <v-expansion-panels class="mb-6">
      <v-expansion-panel>
        <v-expansion-panel-title>
          <v-icon start>mdi-cog</v-icon>
          Security Options
        </v-expansion-panel-title>
        <v-expansion-panel-text>
          <v-switch
            v-model="inboundVerifyPeer"
            label="Verify TLS certificate"
            color="primary"
            hint="Disable only for trusted internal or test environments"
            persistent-hint
            class="mb-4"
          />

          <v-switch
            v-model="inboundVerifyHost"
            label="Verify certificate hostname"
            color="primary"
            hint="Checks that the certificate matches the IMAP host"
            persistent-hint
            class="mb-4"
          />
        </v-expansion-panel-text>
      </v-expansion-panel>
    </v-expansion-panels>

    <v-divider class="mb-6" />

    <!-- ── Outgoing (SMTP) ─────────────────────────────────────────────────── -->
    <div class="d-flex align-center mb-4">
      <v-icon start color="primary">mdi-email-arrow-right</v-icon>
      <span class="text-subtitle-1 font-weight-medium">Outgoing mail (SMTP)</span>
    </div>

    <v-text-field
      v-model="outboundHost"
      label="SMTP Server Host"
      hint="For example: smtp.example.com"
      persistent-hint
      variant="outlined"
      prepend-inner-icon="mdi-server-network"
      class="mb-4"
      autocomplete="off"
      autocorrect="off"
      autocapitalize="none"
      :rules="[rules.required]"
    />

    <v-select
      v-model="outboundEncryption"
      :items="encryptionOptions"
      label="Security"
      variant="outlined"
      prepend-inner-icon="mdi-shield-lock"
      class="mb-4"
    />

    <v-text-field
      v-model="outboundPort"
      label="Port"
      hint="Defaults to 465 for implicit TLS, 587 for STARTTLS, and 25 for plain"
      persistent-hint
      variant="outlined"
      prepend-inner-icon="mdi-numeric"
      class="mb-4"
      type="number"
      min="1"
      max="65535"
      :rules="[rules.required, rules.port]"
    />

    <v-expansion-panels>
      <v-expansion-panel>
        <v-expansion-panel-title>
          <v-icon start>mdi-cog</v-icon>
          Security Options
        </v-expansion-panel-title>
        <v-expansion-panel-text>
          <v-switch
            v-model="outboundVerifyPeer"
            label="Verify TLS certificate"
            color="primary"
            hint="Disable only for trusted internal or test environments"
            persistent-hint
            class="mb-4"
          />

          <v-switch
            v-model="outboundVerifyHost"
            label="Verify certificate hostname"
            color="primary"
            hint="Checks that the certificate matches the SMTP host"
            persistent-hint
            class="mb-4"
          />
        </v-expansion-panel-text>
      </v-expansion-panel>
    </v-expansion-panels>
  </div>
</template>

<style scoped>
.imap-protocol-panel {
  max-width: 800px;
}

.text-h6 {
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 2rem;
  letter-spacing: 0.0125em;
}

.text-body-2 {
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.25rem;
  letter-spacing: 0.0178571429em;
  color: rgba(var(--v-theme-on-surface), 0.7);
}
</style>
