import type { PowerItem } from '@/types/PowerItem'
import axios from 'axios'
import { defineStore } from 'pinia'
import { computed, ref, toRaw } from 'vue'

export const usePowerItems = defineStore('powerItems', () => {
  const BLESSING_POWER_ITEM_STORAGE = 'BLESSING_POWER_ITEM_STORAGE'
  const FELLOW_POWER_ITEM_STORAGE = 'FELLOW_POWER_ITEM_STORAGE'
  const INTIMACY_POWER_ITEM_STORAGE = 'INTIMACY_POWER_ITEM_STORAGE'
  const blessingPowerItems = ref(new Map<string, PowerItem>())
  const fellowPowerItems = ref(new Map<string, PowerItem>())
  const intimacyPowerItems = ref(new Map<string, PowerItem>())
  const isLoadComplete = ref(false)

  async function fetchPowerItems() {
    axios
      .get('/items/blessingPowerItems.json', {
        headers: {
          'Cache-Control': 'no-cache',
          Pragma: 'no-cache',
          Expires: '0'
        }
      })
      .then((resp) => {
        const plainMap = new Map<string, PowerItem>(
          Object.entries(JSON.parse(localStorage.getItem(BLESSING_POWER_ITEM_STORAGE) || '{}'))
        )
        Object.keys(resp.data).map((key) => {
          const cur = resp.data[key]
          if (cur['owned'] === undefined) cur['owned'] = 0
          cur['owned'] = plainMap.get(key) !== undefined ? plainMap.get(key)?.owned : 0
          blessingPowerItems.value.set(key, resp.data[key])
        })
      })
      .catch((err) => {
        console.log(err)
      })
    axios
      .get('/items/fellowPowerItems.json', {
        headers: {
          'Cache-Control': 'no-cache',
          Pragma: 'no-cache',
          Expires: '0'
        }
      })
      .then((resp) => {
        const plainMap = new Map<string, PowerItem>(
          Object.entries(JSON.parse(localStorage.getItem(FELLOW_POWER_ITEM_STORAGE) || '{}'))
        )
        Object.keys(resp.data).map((key) => {
          const cur = resp.data[key]
          if (cur['owned'] === undefined) cur['owned'] = 0
          cur['owned'] = plainMap.get(key) !== undefined ? plainMap.get(key)?.owned : 0
          fellowPowerItems.value.set(key, resp.data[key])
        })
      })
      .catch((err) => {
        console.log(err)
      })
    axios
      .get('/items/intimacyPowerItems.json', {
        headers: {
          'Cache-Control': 'no-cache',
          Pragma: 'no-cache',
          Expires: '0'
        }
      })
      .then((resp) => {
        const plainMap = new Map<string, PowerItem>(
          Object.entries(JSON.parse(localStorage.getItem(INTIMACY_POWER_ITEM_STORAGE) || '{}'))
        )
        Object.keys(resp.data).map((key) => {
          const cur = resp.data[key]
          if (cur['owned'] === undefined) cur['owned'] = 0
          cur['owned'] = plainMap.get(key) !== undefined ? plainMap.get(key)?.owned : 0
          intimacyPowerItems.value.set(key, resp.data[key])
        })
      })
      .catch((err) => {
        console.log(err)
      })
    isLoadComplete.value = true
  }

  function updateOwned(key: string, newOwned: number) {
    let cur = blessingPowerItems.value.get(key)
    if (cur !== undefined) {
      cur.owned = newOwned
      blessingPowerItems.value.set(key, cur)
      localStorage.setItem(
        BLESSING_POWER_ITEM_STORAGE,
        JSON.stringify(mapToObj(toRaw(blessingPowerItems.value)))
      )
      return
    }
    cur = fellowPowerItems.value.get(key)
    if (cur !== undefined) {
      cur.owned = newOwned
      fellowPowerItems.value.set(key, cur)
      localStorage.setItem(
        FELLOW_POWER_ITEM_STORAGE,
        JSON.stringify(mapToObj(toRaw(fellowPowerItems.value)))
      )
    }
    cur = intimacyPowerItems.value.get(key)
    if (cur !== undefined) {
      cur.owned = newOwned
      intimacyPowerItems.value.set(key, cur)
      localStorage.setItem(
        INTIMACY_POWER_ITEM_STORAGE,
        JSON.stringify(mapToObj(toRaw(intimacyPowerItems.value)))
      )
    }
  }

  function mapToObj(map: Map<string, PowerItem>) {
    return Array.from(map).reduce((obj, [key, value]) => {
      // Doing weird magic to work with maps is infuriating, and I haven't found a better solution for this.
      // So ignore that error TypeScript, I (don't) know what I'm doing!
      // @ts-ignore: noImplicitAny
      obj[key] = value
      return obj
    }, {})
  }

  const totalBlessingPower = computed(() =>
    [...blessingPowerItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) => {
        return currentValue !== undefined
          ? accumulator +
              ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned
          : 0
      },
      0
    )
  )

  const standardBlessingItems = computed(
    () => new Map([...blessingPowerItems.value.entries()].filter((cur) => !cur[1].isEventItem))
  )

  const standardBlessingItemTotal = computed(() =>
    [...standardBlessingItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator +
            ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned
          : 0,
      0
    )
  )

  const specialBlessingItems = computed(
    () => new Map([...blessingPowerItems.value.entries()].filter((cur) => cur[1].isEventItem))
  )

  const specialBlessingItemsMinTotal = computed(() =>
    [...specialBlessingItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator + currentValue.minItemPower * currentValue.owned
          : 0,
      0
    )
  )

  const specialBlessingItemsMaxTotal = computed(() =>
    [...specialBlessingItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator + currentValue.maxItemPower * currentValue.owned
          : 0,
      0
    )
  )

  const specialBlessingItemsAveTotal = computed(() =>
    [...specialBlessingItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator +
            ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned
          : 0,
      0
    )
  )

  const totalFellowPower = computed(() =>
    [...fellowPowerItems.value.values()].reduce((accumulator: number, currentValue: PowerItem) => {
      return currentValue !== undefined
        ? accumulator +
            ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned
        : 0
    }, 0)
  )

  const standardFellowItems = computed(
    () => new Map([...fellowPowerItems.value.entries()].filter((cur) => !cur[1].isEventItem))
  )

  const standardFellowItemTotal = computed(() =>
    [...standardFellowItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator +
            ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned
          : 0,
      0
    )
  )

  const specialFellowItems = computed(
    () => new Map([...fellowPowerItems.value.entries()].filter((cur) => cur[1].isEventItem))
  )

  const specialFellowItemsMinTotal = computed(() =>
    [...specialFellowItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator + currentValue.minItemPower * currentValue.owned
          : 0,
      0
    )
  )

  const specialFellowItemsMaxTotal = computed(() =>
    [...specialFellowItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator + currentValue.maxItemPower * currentValue.owned
          : 0,
      0
    )
  )

  const specialFellowItemsAveTotal = computed(() =>
    [...specialFellowItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator +
            ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned
          : 0,
      0
    )
  )

  const totalIntimacyPower = computed(() =>
    [...intimacyPowerItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) => {
        return currentValue !== undefined
          ? accumulator +
              ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned
          : 0
      },
      0
    )
  )

  const standardIntimacyItems = computed(
    () => new Map([...intimacyPowerItems.value.entries()].filter((cur) => !cur[1].isEventItem))
  )

  const standardIntimacyItemTotal = computed(() =>
    [...standardIntimacyItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator +
            ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned
          : 0,
      0
    )
  )

  const specialIntimacyItems = computed(
    () => new Map([...intimacyPowerItems.value.entries()].filter((cur) => cur[1].isEventItem))
  )

  const specialIntimacyItemsMinTotal = computed(() =>
    [...specialIntimacyItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator + currentValue.minItemPower * currentValue.owned
          : 0,
      0
    )
  )

  const specialIntimacyItemsMaxTotal = computed(() =>
    [...specialIntimacyItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator + currentValue.maxItemPower * currentValue.owned
          : 0,
      0
    )
  )

  const specialIntimacyItemsAveTotal = computed(() =>
    [...specialIntimacyItems.value.values()].reduce(
      (accumulator: number, currentValue: PowerItem) =>
        currentValue !== undefined
          ? accumulator +
            ((currentValue.maxItemPower + currentValue.minItemPower) / 2) * currentValue.owned
          : 0,
      0
    )
  )

  fetchPowerItems()

  return {
    blessingPowerItems,
    fellowPowerItems,
    intimacyPowerItems,
    isLoadComplete,
    fetchPowerItems,
    updateOwned,
    totalBlessingPower,
    standardBlessingItems,
    standardBlessingItemTotal,
    specialBlessingItems,
    specialBlessingItemsMinTotal,
    specialBlessingItemsMaxTotal,
    specialBlessingItemsAveTotal,
    totalFellowPower,
    standardFellowItems,
    standardFellowItemTotal,
    specialFellowItems,
    specialFellowItemsMinTotal,
    specialFellowItemsMaxTotal,
    specialFellowItemsAveTotal,
    totalIntimacyPower,
    standardIntimacyItems,
    standardIntimacyItemTotal,
    specialIntimacyItems,
    specialIntimacyItemsMinTotal,
    specialIntimacyItemsMaxTotal,
    specialIntimacyItemsAveTotal
  }
})
