<script setup lang="ts">
import { ref, reactive, computed, watch, onBeforeMount } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { format } from 'date-fns'
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/stores/user'
import type IAccount from '@/models/IAccount'
import type ICurrency from '@/models/ICurrency'
import type ITransaction from '@/models/ITransaction'
import type ISplit from '@/models/ISplit'
import type ILocation from '@/models/ILocation'
import TransactionType from '@/enums/TransactionType'
import TransactionTag, { TransactionTagLabel } from '@/enums/TransactionTag'
import exchangeService from '@/services/ExchangeService'
import transactionService from '@/services/TransactionService'
import mapService from '@/services/MapService'
import { money } from '@/utils/format'
import { findContrastColor } from '@/utils'
import notif from '@/utils/notif'
import { validateAndNotify } from '@/utils/validate'
import { transactionFormSchema, MAX_TRANSACTION_AMOUNT } from '@/schemas/transaction'
import FabButton from '@/components/FabButton.vue'
import TransactionSplit from '@/components/TransactionSplit.vue'
import TransactionTagUpdate from '@/components/TransactionTagUpdate.vue'
import EarthMap from '@/components/EarthMap.vue'
import CurrencyInput from '@/components/CurrencyInput.vue'

const props = defineProps<{
  transaction: ITransaction
  account: IAccount
}>()

const router = useRouter()
const { t } = useI18n()
const userStore = useUserStore()
const { locale } = storeToRefs(userStore)

const formatToDate = (d: Date | string) => format(new Date(d), 'yyyy-MM-dd')
const todayDate = new Date()

const name = ref('')
const amount = ref<number | null>(null)
const tag = ref<TransactionTag>(TransactionTag.None)
const today = formatToDate(todayDate)
const date = ref(today)
const currency = ref<ICurrency | null>(null)
const payBy = ref('')
const payFor = reactive<ISplit[]>([])
const maxAmount = MAX_TRANSACTION_AMOUNT
const displayLocationModal = ref(false)
const isSetLocation = ref(false)
const location = ref<ILocation | null>(null)
const noTag = TransactionTag.None

onBeforeMount(() => {
  setData(props.transaction)
})

const setData = (t: ITransaction) => {
  name.value = t.name
  date.value = formatToDate(t.date)
  tag.value = t.tag
  amount.value = t.amount || null
  payBy.value = t.payBy
  payFor.splice(0, payFor.length, ...t.payFor)
  if (props.account.users) {
    props.account.users.forEach((u) => {
      if (!t.payFor.find((p) => p.alias === u.alias)) {
        payFor.push({ alias: u.alias || '', weight: 0 })
      }
    })
  }
  currency.value = t.mainCurrency
}

const payForUsers = computed(() => payFor.filter((p) => p.weight > 0))

const backgroundColor = computed(() => {
  if (!props.account || !props.account.color) return undefined
  return {
    backgroundColor: props.account.color,
    color: findContrastColor(props.account.color) || 'black'
  }
})

watch(payBy, (newValue, oldValue) => {
  if (oldValue && payFor.length !== props.account.users.length) {
    const old = payFor.find((p) => p.alias === oldValue)
    if (old) old.weight = 0
  }
  if (newValue) {
    const newPayBy = payFor.find((p) => p.alias === newValue)
    if (newPayBy) newPayBy.weight = newPayBy.weight || 1
  }
})

const selectAll = () => {
  payFor.forEach((p) => (p.weight = p.weight || 1))
}

const located = (loc: ILocation) => {
  location.value = loc
}

const validLocation = async () => {
  try {
    isSetLocation.value = true
    if (location.value) {
      const place = await mapService.getPlace(location.value)
      props.transaction.location = { ...location.value, place }
    }
  } catch {
    props.transaction.location = props.transaction.location
  } finally {
    displayLocationModal.value = false
    isSetLocation.value = false
  }
}

const validate = (): boolean => {
  const el = document.querySelector(':focus') as HTMLInputElement | null
  el?.blur()
  return validateAndNotify(
    transactionFormSchema,
    { name: name.value, amount: amount.value, payBy: payBy.value },
    t,
    { amount: { max: money(maxAmount, currency.value) } }
  )
}

const submitTransaction = async (finish: () => void) => {
  if (!validate() || !currency.value || !props.account) {
    finish()
    return
  }
  const currencies = props.account.currencies.map((c) => c.code)
  const d = new Date(date.value)
  d.setHours(todayDate.getHours(), todayDate.getMinutes())
  const hasId = !!props.transaction._id
  const numericAmount = amount.value ? parseFloat(amount.value.toString().replace(',', '.')) : 0
  const transaction: ITransaction = {
    _id: props.transaction._id,
    _rev: props.transaction._rev,
    doctype: props.transaction.doctype,
    accountId: props.account._id || '',
    name: name.value,
    date: d,
    tag: tag.value,
    amount: numericAmount,
    payBy: payBy.value,
    payFor: payForUsers.value,
    userIds: props.account.userIds,
    mainCurrency: currency.value,
    currencies: props.account.currencies,
    transactionType: TransactionType.normal,
    location: props.transaction.location,
    exchange: await exchangeService.get(currency.value.code, d, currencies)
  }
  const response = hasId
    ? await transactionService.save(transaction)
    : await transactionService.add(props.account._id || '', transaction)
  if (response.ok) {
    if (hasId) {
      router.push({ name: 'transaction', params: { id: props.transaction._id || '' } })
      notif.success('Dépense mise à jour.')
    } else {
      router.push({ name: 'account', params: { id: props.account._id || '' } })
      notif.success('Dépense créée.')
    }
  } else {
    console.warn(response)
    notif.error(`Une erreur s'est produite à la création d'une transaction.`)
  }
  finish()
}
</script>

<template>
  <div class="transaction-create">
    <nav v-if="account" class="breadcrumbs text-sm mb-3" aria-label="breadcrumbs">
      <ul>
        <li>
          <router-link :to="{ name: 'account', params: { id: account._id } }">
            {{ account.name }}
          </router-link>
        </li>
        <li v-if="tag && tag !== noTag">
          <a href="#" @click.prevent>{{ TransactionTagLabel[tag].label }}</a>
        </li>
        <li>
          <a href="#" @click.prevent>
            <span v-if="transaction._id">{{ name }}</span>
            <span v-else>Nouvelle dépense</span>
          </a>
        </li>
      </ul>
    </nav>
    <div class="grid md:grid-cols-2 gap-6">
      <div class="space-y-4">
        <div class="flex items-center gap-3">
          <label class="label w-24">Nom</label>
          <div class="flex-1">
            <input
              v-model.trim="name"
              type="text"
              maxlength="30"
              placeholder="Nom de la dépense"
              class="input input-bordered w-full"
            />
            <p class="text-xs text-info mt-1">
              {{ t('validation.max_char', { max: 30 - name.length }, 30 - name.length) }}
            </p>
          </div>
        </div>

        <div class="flex items-center gap-3">
          <label class="label w-24">Montant</label>
          <div class="flex-1">
            <div class="join w-full">
              <CurrencyInput
                v-model="amount"
                :locale="locale"
                :precision="2"
                :allow-negative="false"
                :value-range="{ min: 0, max: 1000000 }"
                placeholder="Montant"
                class="join-item flex-1"
              />
              <span v-if="account.currencies.length > 1" class="join-item">
                <select v-model="currency" name="currency" class="select select-bordered">
                  <option v-for="(c, k) in account.currencies" :key="k" :value="c">
                    {{ c.symbol || c.name }}
                  </option>
                </select>
              </span>
              <span v-else class="btn btn-disabled join-item">
                {{ account.mainCurrency.symbol || account.mainCurrency.name }}
              </span>
            </div>
            <p class="text-xs text-info mt-1">
              montant max : {{ money(maxAmount, currency) }}
            </p>
          </div>
        </div>

        <div class="flex items-center gap-3">
          <label class="label w-24">Localisation</label>
          <div class="flex-1 flex gap-2">
            <input
              v-if="transaction.location"
              :value="transaction.location.place"
              type="text"
              readonly
              class="input input-bordered flex-1"
            />
            <button class="btn btn-primary" @click="displayLocationModal = true">définir</button>
          </div>
        </div>

        <div class="flex items-center gap-3">
          <label class="label w-24">Date</label>
          <input
            v-model="date"
            type="date"
            class="input input-bordered"
            placeholder="Date"
            :max="today"
          />
        </div>

        <TransactionTagUpdate v-model="tag" />
      </div>

      <div v-if="account.users.length > 1" class="space-y-4">
        <div class="flex items-center gap-3">
          <label class="label w-24">Payé par</label>
          <select v-model="payBy" name="pay-by" class="select select-bordered flex-1">
            <option v-for="(u, k) in account.users" :key="k" :value="u.alias">
              {{ u.alias }}
            </option>
          </select>
        </div>
        <div>
          <div class="flex items-center gap-3 mb-2">
            <label class="label w-24">Pour</label>
            <button
              type="button"
              class="btn btn-primary btn-sm"
              :class="{ 'btn-outline': payForUsers.length !== account.users.length }"
              @click="selectAll"
            >
              tous
            </button>
          </div>
          <div class="space-y-2">
            <div v-for="(split, k) in payFor" :key="k" class="user-item">
              <TransactionSplit :split="payFor[k]" />
              <hr v-if="k !== payFor.length - 1" />
            </div>
          </div>
        </div>
      </div>
    </div>

    <dialog class="modal" :class="{ 'modal-open': displayLocationModal }">
      <div class="modal-box max-w-3xl">
        <EarthMap
          v-if="displayLocationModal"
          :locations="transaction.location ? [transaction.location] : undefined"
          :define-location="true"
          @located="located"
        />
        <div class="modal-action">
          <button
            class="btn btn-primary"
            :class="{ 'btn-loading': isSetLocation }"
            @click="validLocation"
          >
            valider
          </button>
          <button class="btn" @click="displayLocationModal = false">annuler</button>
        </div>
      </div>
    </dialog>

    <FabButton :margin="true" :button-style="backgroundColor" @valid="submitTransaction">
      <vaquant-icon icon="check" />
    </FabButton>
  </div>
</template>
