<script setup lang="ts">
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/stores/user'
import { useBaseAccount } from '@/composables/useBaseAccount'
import TransactionType from '@/enums/TransactionType'
import queueNotifService from '@/services/QueueNotifService'
import accountService from '@/services/AccountService'
import balanceService from '@/services/BalanceService'
import transactionService from '@/services/TransactionService'
import exchangeService from '@/services/ExchangeService'
import couchService from '@/services/CouchService'
import type IBalance from '@/models/IBalance'
import type ICurrency from '@/models/ICurrency'
import type IRefund from '@/models/IRefund'
import type IStat from '@/models/IStat'
import type ITransaction from '@/models/ITransaction'
import type IUser from '@/models/IUser'
import type ILocation from '@/models/ILocation'
import { primary, main, findContrastColor, findDarkValue } from '@/utils'

import AccountShare from '@/components/AccountShare.vue'
import AccountTransactionList from '@/components/AccountTransactionList.vue'
import EarthMap from '@/components/EarthMap.vue'
import TagList from '@/components/TagList.vue'
import ChartBalance from '@/components/ChartBalance.vue'
import AccountSetting from '@/components/AccountSetting.vue'
import OnlineView from '@/components/OnlineView.vue'
import RefundTransaction from '@/components/RefundTransaction.vue'
import FabButton from '@/components/FabButton.vue'

const props = defineProps<{ id: string }>()
const router = useRouter()
const userStore = useUserStore()
const { user } = storeToRefs(userStore)

const retrieveTransactions = ref(false)
const transactions = ref<ITransaction[]>([])
const activeTab = ref<'transaction' | 'location' | 'tag' | 'balance' | 'settings'>(
  'transaction'
)
const retrievingExchange = ref(false)

const getData = async (docIds?: string[]): Promise<void> => {
  if (docIds && !docIds.find((i) => i === props.id)) return
  try {
    if (props.id) {
      account.value = await accountService.get(props.id)
      if (!account.value) {
        queueNotifService.error(`le compte ${props.id} n'existe pas`)
        router.push({ name: 'home' })
        return
      }
      if (account.value.isPublic) {
        userStore.addAccountId(props.id)
        couchService.initLive()
      }
      transactions.value = await transactionService.getAllByAccountId(props.id)
      retrieveTransactions.value = true
      if (document.documentElement) {
        if (account.value.color) {
          document.documentElement.style.setProperty('--primary-color', account.value.color)
          document.documentElement.style.setProperty(
            '--primary-font-color',
            findDarkValue(account.value.color) || main
          )
        } else {
          document.documentElement.style.setProperty('--primary-color', primary)
          document.documentElement.style.setProperty('--primary-font-color', main)
        }
      }
      userStore.setTitle(account.value.name)
    }
  } catch (error) {
    console.error({ error })
    router.push({ name: 'home' })
  }
}

const { account, colorStyle } = useBaseAccount(getData)

const toggleTab = (tab: typeof activeTab.value) => {
  activeTab.value = tab
}

const retrieveExchange = async () => {
  if (!transactionWithoutExchange.value.length) return
  retrievingExchange.value = true
  try {
    const list = [...transactionWithoutExchange.value]
    for (const t of list) {
      t.exchange = await exchangeService.get(t.mainCurrency.code, t.date)
    }
    await transactionService.multipleSave(list)
    queueNotifService.success('Dépenses mises à jour.')
  } catch (error) {
    console.warn({ error })
  }
  retrievingExchange.value = false
}

const transactionWithoutRefund = computed(() =>
  transactions.value.filter((t) => t.transactionType === TransactionType.normal)
)
const tagCount = computed(
  () => new Set(transactionWithoutRefund.value.map((t) => t.tag)).size
)
const transactionWithExchange = computed(() =>
  transactions.value.filter((t) => !!t.exchange)
)
const transactionWithoutExchange = computed(() =>
  transactions.value.filter((t) => !t.exchange)
)

const userAlias = computed<string>(() => {
  if (!account.value || !user.value) return ''
  const mainUser = user.value
  const u = account.value.users.find((x) => x.slugEmail === mainUser.slugEmail)
  return u?.alias || ''
})

const totalCost = computed(() => {
  if (!account.value) return 0
  return transactionService.getTotalCost(
    transactionWithExchange.value,
    account.value.mainCurrency.code
  )
})

const userStats = computed<IStat[]>(() => {
  if (!account.value || totalCost.value === 0) return []
  const acc = account.value
  const list = transactionWithExchange.value
  const mainCurrency: ICurrency = acc.mainCurrency
  return acc.users.map((u: IUser) => {
    const userCost = transactionService.getTotalCost(list, acc.mainCurrency.code, u.alias)
    const percent = Math.round((userCost / totalCost.value) * 100)
    return {
      label: u.alias || '',
      value: userCost,
      percent,
      balance: balanceService.getBalanceByUser(u, mainCurrency, list)
    }
  })
})

const locations = computed<ILocation[]>(() =>
  transactions.value
    .filter((t) => t.location)
    .map((t) => t.location as ILocation)
)

const userBalance = computed<IBalance[]>(() => {
  if (!account.value || !account.value.users) return []
  const mainCurrency: ICurrency = account.value.mainCurrency
  const list = transactionWithExchange.value
  return account.value.users.map((u) =>
    balanceService.getBalanceByUser(u, mainCurrency, list)
  )
})

const userRefunds = computed<IRefund[]>(() =>
  account.value ? balanceService.getRefund(userBalance.value) : []
)

const isAdmin = computed(() => {
  if (!account.value || !account.value.admin || !user.value) return true
  return account.value.admin.slugEmail === user.value.slugEmail
})

const isMultiUser = computed(() => !!account.value && account.value.users.length > 1)
const isEncrypted = computed(
  () => !!(account.value && account.value.name.length > 30)
)

const showShare = computed(
  () =>
    !!account.value &&
    account.value.users.length > 1 &&
    retrieveTransactions.value &&
    !transactions.value.length
)

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

<template>
  <section v-if="account" class="account-item p-4">
    <div v-if="isEncrypted" class="alert alert-warning mb-4">
      <span>Compte chiffré</span>
    </div>
    <h2 class="text-3xl font-bold text-center mb-4 account-title">
      <span :style="colorStyle()">{{ account.name }}</span>
    </h2>
    <div v-if="showShare" class="flex justify-center mb-4">
      <div class="w-full md:w-1/3">
        <AccountShare :account="account" />
      </div>
    </div>
    <div v-if="transactionWithoutExchange.length" class="alert alert-warning mb-4">
      <div>
        <p class="font-bold">Attention</p>
        <p>
          Certaines dépenses ne sont pas comptées car en attente de récupérer
          les taux pratiqués à leur date respectives.
        </p>
        <ul class="list-disc list-inside">
          <li v-for="(t, k) in transactionWithoutExchange" :key="k">
            <router-link :to="{ name: 'transaction', params: { id: t._id } }">
              {{ t.name }}
            </router-link>
          </li>
        </ul>
        <OnlineView @online="retrieveExchange">
          <button
            class="btn btn-success btn-lg mt-2"
            :class="{ 'btn-loading': retrievingExchange }"
            @click="retrieveExchange"
          >
            Récupérer les devises
          </button>
        </OnlineView>
      </div>
    </div>
    <div role="tablist" class="tabs tabs-boxed max-w-md mx-auto mb-4">
      <a
        role="tab"
        href="#"
        class="tab"
        :class="{ 'tab-active': activeTab === 'transaction' }"
        :style="colorStyle(activeTab === 'transaction')"
        @click.prevent="toggleTab('transaction')"
      >
        <vaquant-icon icon="currency-dollar" />
      </a>
      <a
        v-if="transactions.length && locations.length"
        role="tab"
        href="#"
        class="tab"
        :class="{ 'tab-active': activeTab === 'location' }"
        :style="colorStyle(activeTab === 'location')"
        @click.prevent="toggleTab('location')"
      >
        <vaquant-icon icon="world" />
      </a>
      <a
        v-if="transactions.length && tagCount > 1"
        role="tab"
        href="#"
        class="tab"
        :class="{ 'tab-active': activeTab === 'tag' }"
        :style="colorStyle(activeTab === 'tag')"
        @click.prevent="toggleTab('tag')"
      >
        <vaquant-icon icon="tag" />
      </a>
      <a
        v-if="transactions.length && isMultiUser"
        role="tab"
        href="#"
        class="tab"
        :class="{ 'tab-active': activeTab === 'balance' }"
        :style="colorStyle(activeTab === 'balance')"
        @click.prevent="toggleTab('balance')"
      >
        <vaquant-icon icon="scale" />
      </a>
      <a
        v-if="isAdmin"
        role="tab"
        href="#"
        class="tab"
        :class="{ 'tab-active': activeTab === 'settings' }"
        :style="colorStyle(activeTab === 'settings')"
        @click.prevent="toggleTab('settings')"
      >
        <vaquant-icon icon="settings" />
      </a>
    </div>

    <div v-if="activeTab === 'transaction'" class="mt-4">
      <AccountTransactionList :account="account" :transactions="transactions" />
    </div>
    <div v-if="activeTab === 'location' && locations.length" class="mt-4">
      <EarthMap :locations="locations" />
    </div>
    <div v-if="activeTab === 'tag'" class="mt-4">
      <TagList :transactions="transactionWithoutRefund" :account="account" />
    </div>
    <div v-if="activeTab === 'balance'" class="mt-4">
      <ChartBalance :account="account" :stats="userStats" :currency="account.mainCurrency" />
      <div v-if="userRefunds.length" class="grid md:grid-cols-3 gap-4 mt-4">
        <div v-for="refund in userRefunds" :key="`${refund.from.alias}-${refund.to.alias}`">
          <RefundTransaction :refund="refund" :account="account" />
        </div>
      </div>
      <div v-else class="text-center text-2xl mt-6">
        Le compte est à l'équilibre&nbsp;!
      </div>
    </div>
    <div v-if="activeTab === 'settings'" class="mt-4">
      <AccountSetting :account="account" />
    </div>

    <FabButton
      v-if="!account.archive"
      :to="{ name: 'transaction-new', params: { id: account._id } }"
      :button-style="backgroundColor"
      :margin="true"
    >
      <vaquant-icon icon="cash" />
      <template #fulltext>dépense</template>
    </FabButton>
  </section>
</template>
