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

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

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

const host = ref('')
const encryption = ref<ImapEncryption>('ssl')
const port = ref('993')
const verifyPeer = ref(true)
const verifyHost = 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 isValid = computed(() => !!host.value && rules.port(port.value) === true)

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

  return {
    type: 'SOCKET_SOLE',
    host: host.value,
    port: Number(port.value),
    encryption: encryption.value,
    verifyPeer: verifyPeer.value,
    verifyHost: verifyHost.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 = createServiceObject(props.service)
    nextService.location = location ? LocationSocketSole.fromJson(location) : null
    emit('update:service', nextService)
  },
  { immediate: true, deep: true }
)

watch(encryption, (next, previous) => {
  const previousDefault = defaultPortFor(previous)
  if (!port.value || Number(port.value) === previousDefault) {
    port.value = String(defaultPortFor(next))
  }
})

function syncFromLocation(location: ServiceLocation | null) {
  const socketLocation = getSocketLocation(location)

  host.value = socketLocation?.host ?? ''
  encryption.value = socketLocation?.encryption ?? 'ssl'
  port.value = String(socketLocation?.port ?? defaultPortFor(encryption.value))
  verifyPeer.value = socketLocation?.verifyPeer ?? true
  verifyHost.value = socketLocation?.verifyHost ?? true
}

function createServiceObject(service?: ServiceObject): ServiceObject {
  const nextService = new ServiceObject()

  if (service) {
    nextService.fromJson(service.toJson())
  }

  return nextService
}

function getSocketLocation(location?: ServiceLocation | null): ServiceLocationSocketSole | null {
  return location?.type === 'SOCKET_SOLE' ? location : null
}

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

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

  return a.host === b.host
    && a.port === b.port
    && a.encryption === b.encryption
    && (a.verifyPeer ?? true) === (b.verifyPeer ?? true)
    && (a.verifyHost ?? true) === (b.verifyHost ?? true)
}

function defaultPortFor(nextEncryption: ImapEncryption): number {
  return nextEncryption === 'ssl' || nextEncryption === 'tls' ? 993 : 143
}
</script>

<template>
  <div class="imap-protocol-panel">
    <h3 class="text-h6 mb-4">IMAP Connection Settings</h3>
    <p class="text-body-2 mb-6">Configure the server address, transport security, and certificate verification for your IMAP mailbox.</p>

    <v-text-field
      v-model="host"
      label="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="encryption"
      :items="encryptionOptions"
      label="Security"
      variant="outlined"
      prepend-inner-icon="mdi-shield-lock"
      class="mb-4"
    />

    <v-text-field
      v-model="port"
      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="mt-4">
      <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="verifyPeer"
            label="Verify TLS certificate"
            color="primary"
            hint="Disable only for trusted internal or test environments"
            persistent-hint
            class="mb-4"
          />

          <v-switch
            v-model="verifyHost"
            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-alert type="info" variant="tonal" density="compact" class="mt-4">
      <template #prepend>
        <v-icon>mdi-information</v-icon>
      </template>
      <div class="text-caption">
        STARTTLS is accepted for compatibility, but the current IMAP client transport does not perform STARTTLS negotiation. Prefer TLS on port 993 when available.
      </div>
    </v-alert>
  </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>