import {
  ACTION_SAVE_KEY,
  ACTION_ROSTER_SAVE_KEY,
  loadActionCharacter,
  loadActionRoster,
  saveActionCharacter,
  saveActionRoster,
  type ActionCharacter,
  type ActionCharacterRoster,
} from './actionMode'
import {
  ACTION_MECHANIC_CONFIG_KEY,
  loadActionMechanicConfig,
  saveActionMechanicConfig,
  type ActionMechanicConfig,
} from './actionBoss/actionEncounterConfig'

const AUTH_TOKEN_KEY = 'i-want-to-heal-2:auth-token:v1'

export type AuthAccount = {
  id: string
  username: string
  displayName: string
}

export type AuthSession = {
  account: AuthAccount | null
  offline?: boolean
  profile?: null
  token?: string
}

export type ActionCloudSave = {
  character?: ActionCharacter
  roster?: ActionCharacterRoster
  mechanics?: ActionMechanicConfig
  updatedAt?: string
}

export type ArenaQueuePlayer = {
  accountId: string
  displayName: string
  side: 'a' | 'b'
  username: string
}

export type ArenaQueueMatch = {
  id: string
  mode: 'arenas'
  createdAt: number
  updatedAt: number
  players: {
    a: ArenaQueuePlayer
    b: ArenaQueuePlayer
  }
}

export type ArenaQueueResponse = {
  ticketId: string
  status: 'waiting' | 'matched'
  side?: 'a' | 'b'
  match?: ArenaQueueMatch
}

type SavedSlotResponse = {
  save: null | {
    save_json?: ActionCloudSave
    saveJson?: ActionCloudSave
  }
}

function configuredBaseUrl(value: string | undefined) {
  return value ? value.replace(/\/+$/, '') : ''
}

function apiBaseUrl() {
  if (typeof window !== 'undefined') {
    const runtimeBase = (window as Window & { CAPACITOR_API_BASE_URL?: string }).CAPACITOR_API_BASE_URL
    if (runtimeBase) return configuredBaseUrl(runtimeBase)
  }
  return configuredBaseUrl(import.meta.env.VITE_API_BASE_URL)
}

function readAuthToken() {
  return window.localStorage.getItem(AUTH_TOKEN_KEY) ?? ''
}

function writeAuthToken(token: string) {
  window.localStorage.setItem(AUTH_TOKEN_KEY, token)
}

export function clearAuthToken() {
  window.localStorage.removeItem(AUTH_TOKEN_KEY)
}

export async function requestActionApiJson<T>(path: string, init: RequestInit = {}): Promise<T> {
  const baseUrl = apiBaseUrl()
  const headers = new Headers(init.headers)
  const token = readAuthToken()
  if (token && !headers.has('Authorization')) headers.set('Authorization', `Bearer ${token}`)
  const response = await fetch(baseUrl ? `${baseUrl}${path}` : path, {
    ...init,
    credentials: 'include',
    headers,
  })
  const body = await response.json().catch(() => ({}))
  if (!response.ok) throw new Error(body.error ?? 'Unable to reach the game server.')
  return body as T
}

export async function loadSession() {
  const session = await requestActionApiJson<AuthSession>('/api/auth/session')
  if (session.token) writeAuthToken(session.token)
  return session
}

export async function loginAccount(username: string, password: string) {
  const session = await requestActionApiJson<AuthSession>('/api/auth/login', {
    body: JSON.stringify({ username, password }),
    headers: { 'Content-Type': 'application/json' },
    method: 'POST',
  })
  if (session.token) writeAuthToken(session.token)
  return session
}

export async function registerAccount(username: string, password: string, characterName: string) {
  const session = await requestActionApiJson<AuthSession>('/api/auth/register', {
    body: JSON.stringify({ username, password, characterName }),
    headers: { 'Content-Type': 'application/json' },
    method: 'POST',
  })
  if (session.token) writeAuthToken(session.token)
  return session
}

export async function logoutAccount() {
  await requestActionApiJson('/api/auth/logout', { method: 'POST' }).catch(() => null)
  clearAuthToken()
}

export function localCloudSave(): ActionCloudSave {
  return {
    character: loadActionCharacter(),
    roster: loadActionRoster(),
    mechanics: loadActionMechanicConfig(),
    updatedAt: new Date().toISOString(),
  }
}

export function applyCloudSave(save: ActionCloudSave) {
  if (save.roster) saveActionRoster(save.roster)
  else if (save.character) saveActionCharacter(save.character)
  if (save.mechanics) saveActionMechanicConfig(save.mechanics)
}

export async function loadCloudSave() {
  const result = await requestActionApiJson<SavedSlotResponse>('/api/save/default')
  return result.save?.save_json ?? result.save?.saveJson ?? null
}

export async function pushCloudSave(save: ActionCloudSave = localCloudSave()) {
  return requestActionApiJson('/api/save/default', {
    body: JSON.stringify({
      clientUpdatedAt: save.updatedAt ?? new Date().toISOString(),
      save,
      saveVersion: 1,
    }),
    headers: { 'Content-Type': 'application/json' },
    method: 'PUT',
  })
}

export function joinArenaQueue() {
  return requestActionApiJson<ArenaQueueResponse>('/api/pvp/queue', {
    body: JSON.stringify({ mode: 'arenas' }),
    headers: { 'Content-Type': 'application/json' },
    method: 'POST',
  })
}

export function checkArenaQueue(ticketId: string) {
  return requestActionApiJson<ArenaQueueResponse>(`/api/pvp/queue/${encodeURIComponent(ticketId)}`)
}

export function cancelArenaQueue(ticketId: string) {
  return requestActionApiJson<{ ok: true }>(`/api/pvp/queue/${encodeURIComponent(ticketId)}`, {
    method: 'DELETE',
  })
}

export async function hydrateLocalSaveFromServer() {
  const remote = await loadCloudSave()
  if (remote) {
    applyCloudSave(remote)
    return 'loaded'
  }
  if (window.localStorage.getItem(ACTION_ROSTER_SAVE_KEY) || window.localStorage.getItem(ACTION_SAVE_KEY) || window.localStorage.getItem(ACTION_MECHANIC_CONFIG_KEY)) {
    await pushCloudSave()
    return 'uploaded'
  }
  return 'empty'
}
