<script setup lang="ts">
import { useHead } from '@unhead/vue';

defineOptions({ name: 'PlayersView' });

import type { QTableColumn } from 'quasar';
import { computed, reactive, ref, watch } from 'vue';
import type { Schemas } from '../../../types';
import { countryOptions, getCountryLabel } from '../../../shared/countries';
import { usePlayersStore } from '../stores/players';

useHead({ title: 'Players' });

type PlayersMap = Schemas.Players;
type Player = PlayersMap[string];

interface PlayerRow extends Player {
  id: string;
}

const playersStore = usePlayersStore();
const rows = computed<PlayerRow[]>(() => playersStore.rows);

const filter = ref('');
const isDialogOpen = ref(false);
const editingId = ref<string | null>(null);
const fileInput = ref<HTMLInputElement | null>(null);

const emptyPlayer: Player = {
  gamertag: '',
  name: '',
  country: '',
  team: '',
  twitter: '',
};

const form = reactive<Player>({ ...emptyPlayer });

const columns: QTableColumn<PlayerRow>[] = [
  { name: 'gamertag', label: 'Gamertag', field: 'gamertag', sortable: true, align: 'left' },
  { name: 'team', label: 'Team', field: 'team', sortable: true, align: 'left' },
  {
    name: 'country',
    label: 'Country',
    field: (row) => getCountryLabel(row.country),
    sortable: true,
    align: 'left',
  },
  { name: 'twitter', label: 'Twitter', field: 'twitter', sortable: true, align: 'left' },
  { name: 'actions', label: 'Actions', field: (row) => row.id, sortable: false, align: 'right' },
];

const filteredCountryOptions = ref(countryOptions);
const countryInput = ref('');
const filterCountries = (value: string, update: (callback: () => void) => void) => {
  update(() => {
    const needle = value.toLowerCase().trim();
    if (!needle) {
      filteredCountryOptions.value = countryOptions;
      return;
    }
    filteredCountryOptions.value = countryOptions.filter((country) =>
      country.label.toLowerCase().includes(needle),
    );
  });
};

watch(
  () => form.country,
  (value) => {
    countryInput.value = getCountryLabel(value);
  },
  { immediate: true },
);

const generateId = () => {
  if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
    return crypto.randomUUID();
  }
  return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
};

const openCreateDialog = () => {
  editingId.value = null;
  Object.assign(form, emptyPlayer);
  isDialogOpen.value = true;
};

const openEditDialog = (row: PlayerRow) => {
  editingId.value = row.id;
  const { id, ...playerData } = row;
  void id;
  Object.assign(form, playerData);
  isDialogOpen.value = true;
};

const savePlayer = () => {
  const id = editingId.value ?? generateId();
  playersStore.upsertPlayer(id, { ...form });
  isDialogOpen.value = false;
};

const deletePlayer = (row: PlayerRow) => {
  const confirmed = window.confirm(`Delete ${row.gamertag || 'this player'}?`);
  if (!confirmed) {
    return;
  }
  playersStore.removePlayer(row.id);
};

const exportPlayers = () => {
  const data = JSON.stringify(playersStore.players, null, 2);
  const blob = new Blob([data], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = 'players.json';
  link.click();
  URL.revokeObjectURL(url);
};

const triggerImport = () => {
  fileInput.value?.click();
};

const handleImport = async (event: Event) => {
  const target = event.target as HTMLInputElement | null;
  const file = target?.files?.[0];
  if (!file) {
    return;
  }
  try {
    const text = await file.text();
    const parsed = JSON.parse(text) as unknown;
    playersStore.setPlayers(parsed as PlayersMap);
  } catch {
    window.alert('Could not import JSON. Check the format.');
  } finally {
    if (target) {
      target.value = '';
    }
  }
};
</script>

<template>
  <QPage class="q-pa-lg players-page">
    <div class="row items-center q-mb-md">
      <div class="text-h4">
        Players
      </div>
      <QSpace />
      <QBtn
        color="primary"
        icon="add"
        label="New player"
        class="q-ml-sm"
        @click="openCreateDialog"
      />
    </div>

    <div class="row items-center q-gutter-sm q-mb-md">
      <QInput
        v-model="filter"
        dense
        outlined
        placeholder="Search..."
        class="players-search"
        clearable
      >
        <template #prepend>
          <QIcon name="search" />
        </template>
      </QInput>
      <QBtn
        color="secondary"
        outline
        icon="file_upload"
        label="Import JSON"
        @click="triggerImport"
      />
      <QBtn
        color="secondary"
        outline
        icon="file_download"
        label="Export JSON"
        @click="exportPlayers"
      />
      <input
        ref="fileInput"
        type="file"
        class="visually-hidden"
        accept="application/json"
        @change="handleImport"
      >
    </div>

    <QTable
      flat
      bordered
      row-key="id"
      :rows="rows"
      :columns="columns"
      :filter="filter"
      :rows-per-page-options="[10, 20, 50]"
    >
      <template #body-cell-actions="{ row }">
        <QTd align="right">
          <QBtn
            size="sm"
            flat
            icon="edit"
            @click="openEditDialog(row)"
          />
          <QBtn
            size="sm"
            flat
            color="negative"
            icon="delete"
            @click="deletePlayer(row)"
          />
        </QTd>
      </template>
    </QTable>

    <QDialog v-model="isDialogOpen">
      <QCard class="players-dialog">
        <QCardSection>
          <div class="text-h6">
            {{ editingId ? 'Edit player' : 'New player' }}
          </div>
        </QCardSection>
        <QSeparator />
        <QCardSection>
          <QForm @submit.prevent="savePlayer">
            <div class="row q-col-gutter-md">
              <div class="col-12">
                <QInput
                  v-model="form.gamertag"
                  label="Gamertag"
                  dense
                  outlined
                  autofocus
                />
              </div>
              <div class="col-12">
                <QInput
                  v-model="form.name"
                  label="Name"
                  dense
                  outlined
                />
              </div>
              <div class="col-12">
                <QSelect
                  v-model="form.country"
                  v-model:input-value="countryInput"
                  :options="filteredCountryOptions"
                  option-value="value"
                  option-label="label"
                  emit-value
                  map-options
                  use-input
                  input-debounce="0"
                  hide-selected
                  fill-input
                  clearable
                  label="Country"
                  dense
                  outlined
                  @filter="filterCountries"
                />
              </div>
              <div class="col-12">
                <QInput
                  v-model="form.team"
                  label="Team"
                  dense
                  outlined
                />
              </div>
              <div class="col-12">
                <QInput
                  v-model="form.twitter"
                  label="Twitter"
                  dense
                  outlined
                />
              </div>
            </div>
          </QForm>
        </QCardSection>
        <QSeparator />
        <QCardActions align="right">
          <QBtn
            flat
            label="Cancel"
            color="secondary"
            @click="isDialogOpen = false"
          />
          <QBtn
            color="primary"
            label="Save"
            @click="savePlayer"
          />
        </QCardActions>
      </QCard>
    </QDialog>
  </QPage>
</template>

<style scoped>
.players-page {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.players-search {
  min-width: 240px;
}

.players-dialog {
  min-width: 320px;
  width: min(720px, 90vw);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}
</style>
