import { defineStore } from 'pinia'
import { reactive } from 'vue'
import { components, getPackages } from '@/api'

interface PackageFilters {
  status?: components['schemas']['Package']['status'][]
  pkgbase?: components['schemas']['Package']['pkgbase']
  exact?: boolean
  repo?: components['schemas']['Package']['repo']
}

export const usePackagesStore = defineStore('packages', () => {
  const state = reactive({
    packages: [] as components['schemas']['Package'][],
    currentlyBuildingPackages: [] as components['schemas']['Package'][],
    total: 0,
    offset: 0,
    limit: Number(import.meta.env.VITE_LIMIT) || 50,
    loading: false,
    loadingCurrentlyBuilding: false,
    error: null as string | null,
    errorCurrentlyBuilding: null as string | null,
    lastUpdated: Date.now(),
    filters: {
      status: undefined,
      pkgbase: undefined,
      exact: undefined,
      repo: undefined
    } as PackageFilters
  })

  // Actions
  const fetchPackages = (init = false) => {
    state.loading = true
    state.error = null
    state.packages = []
    state.total = 0

    if (init) {
      initFromUrl()
    }

    const filter: PackageFilters = {}
    if (state.filters.status && state.filters.status.length > 0) {
      filter.status = state.filters.status
    }
    if (state.filters.pkgbase) {
      filter.pkgbase = state.filters.pkgbase
    }
    if (state.filters.exact === true) {
      filter.exact = state.filters.exact
    }
    if (state.filters.repo) {
      filter.repo = state.filters.repo
    }

    getPackages({
      limit: state.limit,
      offset: state.offset,
      ...filter
    } as Parameters<typeof getPackages>[0])
      .then((response) => {
        if (!response) throw new Error('No response from API')
        state.packages = response.packages || []
        state.total = response.total || 0
        state.offset = response.offset || 0
        state.limit = response.limit || state.limit
      })
      .catch((err) => {
        if (err.statusCode === 404) {
          state.packages = []
          state.total = 0
          state.offset = 0
          state.limit = Number(import.meta.env.VITE_LIMIT) || 50
        } else {
          state.error = err instanceof Error ? err.message : 'Failed to fetch packages'
        }
      })
      .finally(() => {
        state.loading = false
      })
  }

  const fetchCurrentlyBuilding = () => {
    state.loadingCurrentlyBuilding = true
    state.errorCurrentlyBuilding = null
    state.currentlyBuildingPackages = []

    getPackages({
      limit: 0,
      offset: 0,
      status: ['queued', 'building', 'built']
    })
      .then((response) => {
        state.currentlyBuildingPackages = response?.packages || []
      })
      .catch((err) => {
        if (err.statusCode === 404) {
          state.currentlyBuildingPackages = []
        } else {
          state.errorCurrentlyBuilding =
            err instanceof Error ? err.message : 'Failed to fetch currently building packages'
        }
      })
      .finally(() => {
        state.loadingCurrentlyBuilding = false
        state.lastUpdated = Date.now()
      })
  }

  const goToPage = (page: number) => {
    state.offset = (page - 1) * state.limit

    updateUrlParams()
    fetchPackages()
  }

  const setFilters = (newFilters: PackageFilters, page?: number) => {
    state.filters = structuredClone(newFilters)
    if (state.filters.exact === false) {
      state.filters.exact = undefined
    }
    if (page) {
      state.offset = (page - 1) * state.limit
    }

    updateUrlParams()
    fetchPackages()
  }

  const resetFilters = () => {
    state.filters = {
      status: undefined,
      pkgbase: undefined,
      exact: undefined,
      repo: undefined
    }
    state.offset = 0
    state.limit = Number(import.meta.env.VITE_LIMIT) || 50

    updateUrlParams()
    fetchPackages()
  }

  const updateUrlParams = () => {
    const params = new URLSearchParams()

    const page = state.offset / state.limit + 1
    // Only add a page parameter if it's not the first page
    if (page > 1) {
      params.set('page', page.toString())
    }

    if (state.filters.status && state.filters.status.length > 0) {
      state.filters.status.forEach((status: components['schemas']['Package']['status']) => {
        if (status) {
          params.append('status', status)
        }
      })
    }

    if (state.filters.pkgbase) {
      params.set('pkgbase', state.filters.pkgbase.toLowerCase())
    }

    if (state.filters.repo) {
      params.set('repo', state.filters.repo)
    }

    if (state.filters.exact === true) {
      params.set('exact', '')
    } else {
      params.delete('exact')
    }

    const paramsString = params.toString()
    if (paramsString) {
      window.history.pushState(null, '', `${window.location.pathname}?${paramsString}`)
    } else {
      window.history.pushState(null, '', window.location.pathname)
    }
  }

  const initFromUrl = () => {
    const urlParams = new URLSearchParams(window.location.search)

    if (urlParams.has('page')) {
      const pageParam = urlParams.get('page') || '1'
      const parsedPage = parseInt(pageParam, 10)
      const page = !isNaN(parsedPage) && parsedPage > 0 ? parsedPage : 1
      state.offset = (page - 1) * state.limit
    }

    if (urlParams.has('status')) {
      const status = urlParams.getAll('status')
      state.filters.status = status as components['schemas']['Package']['status'][]
    }

    if (urlParams.has('pkgbase')) {
      const pkgbase = urlParams.get('pkgbase')
      if (pkgbase === null) return
      state.filters.pkgbase = pkgbase as components['schemas']['Package']['pkgbase']
    }

    if (urlParams.has('repo')) {
      const repo = urlParams.get('repo')
      if (repo === null) return
      state.filters.repo = repo as components['schemas']['Package']['repo']
    }

    if (urlParams.has('exact')) {
      state.filters.exact = true
    }
  }

  return {
    state,

    // Actions
    fetchPackages,
    fetchCurrentlyBuilding,
    goToPage,
    setFilters,
    resetFilters
  }
})
