import { defineStore } from 'pinia'

import { api } from '../lib/api'
import {
  classifyPublicLoadError,
  createAwardsState,
  createEmptyAdminDashboard,
  createEmptyAdminRiskFlagsResponse,
  createEmptyAdminSeasonDetail,
  createEmptyAdminSiteSettings,
  createEmptyArchive,
  createEmptyDatabaseHealth,
  normalizeSeasonDetail,
} from './awards/defaults'
import type {
  ApproveNominationPayload,
  CreateSeasonPayload,
  CreateClipPayload,
  CreateNominationPayload,
  CreateVotePayload,
  RejectNominationPayload,
  ResolveRiskFlagPayload,
  SetAwardResultPayload,
  AdminAuditQueryOptions,
  AdminRiskQueryOptions,
  UpdateSeasonPayload,
  UpdateClipStatusPayload,
  UpdateSiteSettingsPayload,
  UpsertCandidatePayload,
  UpsertCategoryPayload,
} from '../types/awards'

interface AdminSeasonRefreshOptions {
  reloadAdmin?: boolean
  reloadHome?: boolean
}

export const useAwardsStore = defineStore('awards', {
  state: createAwardsState,
  actions: {
    async loadHomeData() {
      this.loading = true
      this.lastPublicError = null
      this.lastPublicErrorKind = null
      try {
        this.overview = await api.getOverview()
        this.categories = await api.getSeasonCategories(this.overview.year)
        const overviewArchiveYears = this.overview.archiveYears ?? []
        const initialArchiveYear = overviewArchiveYears[0]?.year
          ?? this.overview.winnersPreview[0]?.year
          ?? this.overview.year - 1
        this.archive = await api.getWinnerArchive(initialArchiveYear)
        this.apiMode = 'api'
      } catch (error) {
        this.apiMode = 'fallback'
        const { message, kind } = classifyPublicLoadError(error)
        if (kind) {
          this.lastPublicError = message
          this.lastPublicErrorKind = kind
        }
      } finally {
        this.loading = false
      }
    },
    async loadArchive(year: number) {
      try {
        this.archive = await api.getWinnerArchive(year)
        this.apiMode = 'api'
      } catch {
        this.archive = createEmptyArchive(year)
      }
    },
    async loadAdmin() {
      try {
        const [admin, adminSeasons, adminSiteSettings, databaseHealth] = await Promise.all([
          api.getAdminDashboard(),
          api.getAdminSeasons(),
          api.getAdminSiteSettings(),
          api.getDatabaseHealth(),
        ])

        this.admin = admin
        this.adminSeasons = adminSeasons
        this.adminSiteSettings = adminSiteSettings
        this.databaseHealth = databaseHealth

        if (!this.adminSelectedSeasonId || !this.adminSeasons.some((season) => season.id === this.adminSelectedSeasonId)) {
          this.adminSelectedSeasonId = this.adminSeasons[0]?.id ?? null
        }

        if (this.adminSelectedSeasonId) {
          this.adminSeasonDetail = normalizeSeasonDetail(await api.getAdminSeasonDetail(this.adminSelectedSeasonId))
        } else {
          this.adminSeasonDetail = createEmptyAdminSeasonDetail()
        }
        this.apiMode = 'api'
      } catch {
        this.admin = createEmptyAdminDashboard()
        this.adminSeasons = []
        this.adminSeasonDetail = createEmptyAdminSeasonDetail()
        this.adminSiteSettings = createEmptyAdminSiteSettings()
        this.adminRiskHistory = []
        this.adminRiskFlagsPage = createEmptyAdminRiskFlagsResponse()
        this.adminRiskHistoryPage = createEmptyAdminRiskFlagsResponse()
        this.databaseHealth = createEmptyDatabaseHealth()
        this.adminSelectedSeasonId = null
      }
    },
    async loadAdminContentWorkspace() {
      try {
        const [adminSiteSettings, databaseHealth] = await Promise.all([
          api.getAdminSiteSettings(),
          api.getDatabaseHealth(),
        ])

        this.adminSiteSettings = adminSiteSettings
        this.databaseHealth = databaseHealth
        this.apiMode = 'api'
      } catch {
        this.adminSiteSettings = createEmptyAdminSiteSettings()
        this.databaseHealth = createEmptyDatabaseHealth()
      }
    },
    async loadDatabaseHealth() {
      this.databaseHealth = await api.getDatabaseHealth()
      return this.databaseHealth
    },
    async loadAdminSeasonDetail(seasonId: number) {
      try {
        this.adminSelectedSeasonId = seasonId
        this.adminSeasonDetail = normalizeSeasonDetail(await api.getAdminSeasonDetail(seasonId))
        this.apiMode = 'api'
      } catch {
        this.adminSeasonDetail = createEmptyAdminSeasonDetail()
      }
    },
    async initializeAdminWorkspace() {
      await this.loadAdmin()
      if (this.adminSelectedSeasonId && this.adminSeasonDetail.id !== this.adminSelectedSeasonId) {
        await this.loadAdminSeasonDetail(this.adminSelectedSeasonId)
      }
    },
    async refreshAdminSeasonWorkspace(seasonId: number, options: AdminSeasonRefreshOptions = {}) {
      this.adminSelectedSeasonId = seasonId
      if (options.reloadAdmin) {
        await this.loadAdmin()
      } else {
        await this.loadAdminSeasonDetail(seasonId)
      }

      if (options.reloadHome) {
        await this.loadHomeData()
      }
    },
    async refreshAfterSeasonListMutation(options: Pick<AdminSeasonRefreshOptions, 'reloadHome'> = {}) {
      await this.loadAdmin()
      if (options.reloadHome) {
        await this.loadHomeData()
      }
    },
    async loadAdminAuditEntries(limit = 200, query = '') {
      const auditEntries = await api.getAdminAuditEntries(limit, query)
      this.admin = { ...this.admin, auditEntries }
      return auditEntries
    },
    async loadAdminAuditEntriesPage(options: AdminAuditQueryOptions = {}, append = false) {
      const response = await api.getAdminAuditEntriesPage(options)
      this.admin = {
        ...this.admin,
        auditEntries: append ? [...this.admin.auditEntries, ...response.items] : response.items,
      }
      return response
    },
    async loadAdminRiskFlags(limit = 200, status = 'open', query = '') {
      const response = await this.loadAdminRiskFlagsPage({ limit, status, query })
      return response.items
    },
    async loadAdminRiskFlagsPage(options: AdminRiskQueryOptions = {}) {
      const response = await api.getAdminRiskFlagsPage(options)
      this.adminRiskFlagsPage = response
      if ((options.status ?? 'open') === 'open' && !options.reviewedOnly) {
        this.admin = { ...this.admin, riskFlags: response.items }
      }
      return response
    },
    async loadAdminRiskHistory(limit = 80, query = '') {
      const response = await this.loadAdminRiskHistoryPage({ limit, query })
      return response.items
    },
    async loadAdminRiskHistoryPage(options: AdminRiskQueryOptions = {}) {
      const response = await api.getAdminRiskFlagsPage({
        ...options,
        status: options.status ?? 'all',
        reviewedOnly: true,
      })
      this.adminRiskHistoryPage = response
      this.adminRiskHistory = response.items
      return response
    },
    setAdminSeason(seasonId: number) {
      this.adminSelectedSeasonId = seasonId
    },
    submitNomination(payload: CreateNominationPayload) {
      return api.submitNomination(payload)
    },
    submitVote(payload: CreateVotePayload) {
      return api.submitVote(payload)
    },
    submitClip(payload: CreateClipPayload) {
      return api.submitClip(payload)
    },
    async updateAdminSeason(seasonId: number, payload: UpdateSeasonPayload) {
      const result = await api.updateAdminSeason(seasonId, payload)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadAdmin: true, reloadHome: true })
      return result
    },
    async createAdminSeason(payload: CreateSeasonPayload) {
      const result = await api.createAdminSeason(payload)
      await this.refreshAdminSeasonWorkspace(result.seasonId, { reloadAdmin: true, reloadHome: true })
      return result
    },
    async deleteAdminSeason(seasonId: number) {
      const result = await api.deleteAdminSeason(seasonId)
      await this.refreshAfterSeasonListMutation({ reloadHome: true })
      return result
    },
    async createAdminCategory(seasonId: number, payload: UpsertCategoryPayload) {
      const result = await api.createAdminCategory(seasonId, payload)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadHome: true })
      return result
    },
    async updateAdminCategory(categoryId: number, seasonId: number, payload: UpsertCategoryPayload) {
      const result = await api.updateAdminCategory(categoryId, payload)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadHome: true })
      return result
    },
    async createAdminCandidate(seasonId: number, payload: UpsertCandidatePayload) {
      const result = await api.createAdminCandidate(seasonId, payload)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadHome: true })
      return result
    },
    async updateAdminCandidate(candidateId: number, seasonId: number, payload: UpsertCandidatePayload) {
      const result = await api.updateAdminCandidate(candidateId, payload)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadHome: true })
      return result
    },
    async deleteAdminCandidate(candidateId: number, seasonId: number) {
      const result = await api.deleteAdminCandidate(candidateId)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadHome: true })
      return result
    },
    async deleteAdminCategory(categoryId: number, seasonId: number) {
      const result = await api.deleteAdminCategory(categoryId)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadHome: true })
      return result
    },
    async deleteAdminClip(clipId: number, seasonId: number) {
      const result = await api.deleteAdminClip(clipId)
      await this.refreshAdminSeasonWorkspace(seasonId)
      return result
    },
    async updateAdminClipStatus(clipId: number, seasonId: number, payload: UpdateClipStatusPayload) {
      const result = await api.updateAdminClipStatus(clipId, payload)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadAdmin: true })
      return result
    },
    async bulkUpdateAdminClipStatus(clipIds: number[], seasonId: number, status: 'approved' | 'rejected', reviewNote?: string) {
      await Promise.allSettled(clipIds.map((id) => api.updateAdminClipStatus(id, { status, reviewNote })))
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadAdmin: true })
    },
    async setAdminResult(seasonId: number, payload: SetAwardResultPayload) {
      const result = await api.setAdminResult(seasonId, payload)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadAdmin: true, reloadHome: true })
      return result
    },
    async deleteAdminResult(resultId: number, seasonId: number) {
      const result = await api.deleteAdminResult(resultId)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadAdmin: true, reloadHome: true })
      return result
    },
    async approveAdminNomination(nominationId: number, seasonId: number, payload: ApproveNominationPayload) {
      const result = await api.approveAdminNomination(nominationId, payload)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadAdmin: true, reloadHome: true })
      return result
    },
    async rejectAdminNomination(nominationId: number, seasonId: number, payload: RejectNominationPayload) {
      const result = await api.rejectAdminNomination(nominationId, payload)
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadAdmin: true })
      return result
    },
    async bulkRejectAdminNominations(nominationIds: number[], seasonId: number, reviewNote?: string) {
      await Promise.allSettled(nominationIds.map((id) => api.rejectAdminNomination(id, { reviewNote })))
      await this.refreshAdminSeasonWorkspace(seasonId, { reloadAdmin: true })
    },
    async resolveRiskFlag(riskFlagId: number, payload: ResolveRiskFlagPayload) {
      const result = await api.resolveRiskFlag(riskFlagId, payload)
      await Promise.all([
        this.loadAdminRiskFlagsPage({
          limit: this.adminRiskFlagsPage.limit || 25,
          offset: this.adminRiskFlagsPage.offset,
          status: 'open',
        }),
        this.loadAdminRiskHistoryPage({
          limit: this.adminRiskHistoryPage.limit || 25,
          offset: this.adminRiskHistoryPage.offset,
        }),
      ])
      return result
    },
    async bulkResolveRiskFlags(payload: import('../types/awards').BulkResolveRiskFlagsPayload) {
      const result = await api.bulkResolveRiskFlags(payload)
      await Promise.all([
        this.loadAdminRiskFlagsPage({
          limit: this.adminRiskFlagsPage.limit || 25,
          offset: this.adminRiskFlagsPage.offset,
          status: 'open',
        }),
        this.loadAdminRiskHistoryPage({
          limit: this.adminRiskHistoryPage.limit || 25,
          offset: this.adminRiskHistoryPage.offset,
        }),
      ])
      return result
    },
    async loadAdminRiskRules() {
      return api.getAdminRiskRules()
    },
    async updateAdminRiskRules(payload: import('../types/awards').UpdateRiskRulesPayload) {
      return api.updateAdminRiskRules(payload)
    },
    async updateAdminSiteSettings(payload: UpdateSiteSettingsPayload) {
      const result = await api.updateAdminSiteSettings(payload)
      this.adminSiteSettings = await api.getAdminSiteSettings()
      await this.loadHomeData()
      return result
    },
  },
})

export type AwardsStore = ReturnType<typeof useAwardsStore>
