<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import {
  IdentityBasic,
  IdentityOAuth,
  IdentityToken,
} from '@KTXM/MailManager/models/identity'
import type { ServiceObject } from '@KTXM/MailManager/models/service'
import type { ServiceIdentity } from '@KTXM/MailManager/types/service'
import type { ProviderAuthPanelProps, ProviderAuthPanelEmits } from '@KTXM/MailManager/types/integration'
import { JmapServiceObject } from '@/models/JmapServiceObject'

const props = defineProps<ProviderAuthPanelProps>()
const emit = defineEmits<ProviderAuthPanelEmits>()

const authType = ref<'BA' | 'TA' | 'OA'>('BA')
const basicIdentity = ref('')
const basicSecret = ref('')
const bearerToken = ref('')
const oauthLoading = ref(false)
const oauthSuccess = ref(false)
const oauthAccessToken = ref('')
const oauthRefreshToken = ref('')

const rules = {
  required: (value: unknown) => !!value || 'This field is required'
}

const isValid = computed(() => {
  switch (authType.value) {
    case 'BA':
      return !!basicIdentity.value && !!basicSecret.value
    case 'TA':
      return !!bearerToken.value
    case 'OA':
      return oauthSuccess.value && !!oauthAccessToken.value
    default:
      return false
  }
})

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

  switch (authType.value) {
    case 'BA':
      return {
        type: 'BA',
        identity: basicIdentity.value,
        secret: basicSecret.value,
      }
    case 'TA':
      return {
        type: 'TA',
        token: bearerToken.value,
      }
    case 'OA':
      return {
        type: 'OA',
        accessToken: oauthAccessToken.value,
        refreshToken: oauthRefreshToken.value || undefined,
        accessScope: ['mail'],
        accessExpiry: Math.floor(Date.now() / 1000) + 3600,
      }
    default:
      return null
  }
})

watch(
  () => props.service,
  service => {
    syncFromService(service)
  },
  { immediate: true }
)

watch(
  () => props.emailAddress,
  email => {
    if (authType.value === 'BA' && email && !basicIdentity.value) {
      basicIdentity.value = email
    }
  },
  { immediate: true }
)

watch(
  currentIdentity,
  identity => {
    const existingIdentity = props.service?.identity?.toJson() ?? null
    if (sameIdentity(existingIdentity, identity)) {
      return
    }

    const nextService = createServiceObject(props.service)
    nextService.identity = createIdentityModel(identity)
    emit('update:service', nextService)
  },
  { immediate: true, deep: true }
)

function syncFromService(service?: ServiceObject) {
  const identity = service?.identity?.toJson() ?? null

  if (!identity) {
    authType.value = 'BA'
    basicIdentity.value = props.prefilledIdentity || props.emailAddress || ''
    basicSecret.value = props.prefilledSecret || ''
    bearerToken.value = ''
    oauthAccessToken.value = ''
    oauthRefreshToken.value = ''
    oauthSuccess.value = false
    return
  }

  authType.value = identity.type as 'BA' | 'TA' | 'OA'

  switch (identity.type) {
    case 'BA':
      basicIdentity.value = identity.identity || props.prefilledIdentity || props.emailAddress || ''
      basicSecret.value = identity.secret || props.prefilledSecret || ''
      bearerToken.value = ''
      oauthAccessToken.value = ''
      oauthRefreshToken.value = ''
      oauthSuccess.value = false
      break
    case 'TA':
      basicIdentity.value = props.prefilledIdentity || props.emailAddress || ''
      basicSecret.value = props.prefilledSecret || ''
      bearerToken.value = identity.token || ''
      oauthAccessToken.value = ''
      oauthRefreshToken.value = ''
      oauthSuccess.value = false
      break
    case 'OA':
      basicIdentity.value = props.prefilledIdentity || props.emailAddress || ''
      basicSecret.value = props.prefilledSecret || ''
      bearerToken.value = ''
      oauthAccessToken.value = identity.accessToken || ''
      oauthRefreshToken.value = identity.refreshToken || ''
      oauthSuccess.value = !!identity.accessToken
      break
  }
}

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

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

  return nextService
}

function createIdentityModel(identity: ServiceIdentity | null) {
  if (identity === null) {
    return null
  }

  switch (identity.type) {
    case 'BA':
      return new IdentityBasic(identity.identity, identity.secret)
    case 'TA':
      return new IdentityToken(identity.token)
    case 'OA':
      return new IdentityOAuth(
        identity.accessToken,
        identity.accessScope,
        identity.accessExpiry,
        identity.refreshToken,
        identity.refreshLocation
      )
  }
}

function sameIdentity(a: ServiceIdentity | null, b: ServiceIdentity | null): boolean {
  if (a === null || b === null) {
    return a === b
  }

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

  switch (a.type) {
    case 'BA':
      return b.type === 'BA'
        && a.identity === b.identity
        && a.secret === b.secret
    case 'TA':
      return b.type === 'TA'
        && a.token === b.token
    case 'OA':
      return b.type === 'OA'
        && a.accessToken === b.accessToken
        && a.refreshToken === b.refreshToken
    default:
      return false
  }
}

async function initiateOAuth() {
  oauthLoading.value = true

  try {
    throw new Error('OAuth implementation pending')
  } catch (error) {
    console.warn('[JMAP Auth Panel] OAuth implementation pending', error)
  } finally {
    oauthLoading.value = false
  }
}
</script>

<template>
  <div class="jmap-auth-panel">
    <h3 class="text-h6 mb-4">Authentication</h3>
    <p class="text-body-2 mb-6">Choose your authentication method and enter your credentials.</p>

    <v-alert type="info" variant="tonal" class="mb-4">
      <template #prepend>
        <v-icon>mdi-information</v-icon>
      </template>
      <div class="text-caption">
        JMAP supports multiple authentication methods. Choose the one your server uses.
      </div>
    </v-alert>

    <!-- Authentication Type Selection -->
    <div class="mb-4">
      <label class="text-subtitle-2 mb-2 d-block">Authentication Method</label>
      <v-btn-toggle
        v-model="authType"
        color="primary"
        variant="outlined"
        mandatory
        divided
        class="mb-4"
      >
        <v-btn value="BA">
          <v-icon start>mdi-account-key</v-icon>
          Basic Auth
        </v-btn>
        <v-btn value="TA">
          <v-icon start>mdi-key</v-icon>
          Bearer Token
        </v-btn>
        <v-btn value="OA">
          <v-icon start>mdi-shield-account</v-icon>
          OAuth 2.0
        </v-btn>
      </v-btn-toggle>
    </div>

    <!-- Basic Authentication -->
    <template v-if="authType === 'BA'">
      <v-text-field
        v-model="basicIdentity"
        label="Username / Email"
        hint="Your account username or email address"
        persistent-hint
        variant="outlined"
        prepend-inner-icon="mdi-account"
        class="mb-4"
        autocomplete="username"
        autocorrect="off"
        autocapitalize="none"
        :rules="[rules.required]"
      />

      <v-text-field
        v-model="basicSecret"
        type="password"
        label="Password"
        hint="Your account password"
        persistent-hint
        variant="outlined"
        prepend-inner-icon="mdi-lock"
        class="mb-4"
        autocomplete="current-password"
        :rules="[rules.required]"
      />
    </template>

    <!-- Bearer Token Authentication -->
    <template v-else-if="authType === 'TA'">
      <v-textarea
        v-model="bearerToken"
        label="Bearer Token"
        hint="Enter your API token or bearer token"
        persistent-hint
        variant="outlined"
        prepend-inner-icon="mdi-key"
        class="mb-4"
        rows="3"
        autocomplete="off"
        autocorrect="off"
        autocapitalize="none"
        :rules="[rules.required]"
      />
    </template>

    <!-- OAuth 2.0 -->
    <template v-else-if="authType === 'OA'">
      <v-alert type="warning" variant="tonal" class="mb-4">
        <template #prepend>
          <v-icon>mdi-alert</v-icon>
        </template>
        <div class="text-caption">
          OAuth 2.0 implementation is pending. This will launch a browser window 
          for secure authentication with your JMAP provider.
        </div>
      </v-alert>

      <v-btn
        v-if="!oauthSuccess"
        color="primary"
        size="large"
        block
        @click="initiateOAuth"
        :loading="oauthLoading"
        :disabled="true"
      >
        <v-icon start>mdi-login</v-icon>
        Authorize with OAuth 2.0
      </v-btn>

      <div v-else class="text-center py-4">
        <v-icon color="success" size="64">mdi-check-circle</v-icon>
        <p class="text-subtitle-1 mt-2">OAuth Authorized Successfully</p>
      </div>
    </template>
  </div>
</template>

<style scoped>
.jmap-auth-panel {
  max-width: 800px;
}

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

.text-subtitle-2 {
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.375rem;
  letter-spacing: 0.00714em;
}

.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>
