<script setup lang="ts">
import { computed, ref, watch, watchEffect, type Ref } from 'vue';
import type { Schemas } from '../../../types';
import { countryOptions, getCountryLabel } from '../../../shared/countries';
import { usePlayersStore } from '../stores/players';
import { useScoreboardStore } from '../stores/scoreboard';

const playersStore = usePlayersStore();
const scoreboardStore = useScoreboardStore();

const CUSTOM_LEFT_PLAYER_ID = '__custom_left_player__';
const CUSTOM_RIGHT_PLAYER_ID = '__custom_right_player__';

const leftFilter = ref('');
const rightFilter = ref('');
const leftInput = ref('');
const rightInput = ref('');
const leftFocused = ref(false);
const rightFocused = ref(false);

const leftCountryInput = ref('');
const rightCountryInput = ref('');
const leftCountryOptions = ref(countryOptions);
const rightCountryOptions = ref(countryOptions);

const fightingGameOptions = [
  'Street Fighter 6',
  'TEKKEN 8',
  'Guilty Gear -Strive-',
  'Mortal Kombat 1',
  'The King of Fighters XV',
  'Granblue Fantasy Versus: Rising',
  'Under Night In-Birth II Sys:Celes',
].map((game) => ({
  label: game,
  value: game,
}));

const normalizeName = (value: string) => value.trim().toLowerCase();

const filterOptions = (
  options: { label: string; value: string }[],
  needle: string,
) => {
  if (!needle) {
    return options;
  }
  const lowerNeedle = needle.toLowerCase();
  return options.filter((option) => option.label.toLowerCase().includes(lowerNeedle));
};

const filterCountries = (
  value: string,
  update: (callback: () => void) => void,
  target: Ref<{ value: string; label: string }[]>,
) => {
  update(() => {
    const needle = value.toLowerCase().trim();
    if (!needle) {
      target.value = countryOptions;
      return;
    }
    target.value = countryOptions.filter((country) => country.label.toLowerCase().includes(needle));
  });
};


const onLeftCountryFilter = (value: string, update: (callback: () => void) => void) => {
  filterCountries(value, update, leftCountryOptions);
};

const onRightCountryFilter = (value: string, update: (callback: () => void) => void) => {
  filterCountries(value, update, rightCountryOptions);
};

const playerOptions = computed(() => {
  const base = [{ label: '(Sin asignar)', value: '' }];
  const entries = Object.entries(playersStore.players) as [string, Schemas.Players[string]][];
  const options = entries.map(([id, player]) => ({
    value: id,
    label: player.gamertag || id,
  }));
  return base.concat(options);
});

const buildPlayerOptions = (
  filterValue: string,
  selectedPlayerId: string,
  customPlayerId: string,
  customNameOverride: string,
) => {
  const options = filterOptions(playerOptions.value, filterValue);
  if (selectedPlayerId !== customPlayerId || !customNameOverride.trim()) {
    return options;
  }
  return [{
    value: customPlayerId,
    label: customNameOverride,
  }].concat(options);
};

const leftPlayerOptions = computed(() => buildPlayerOptions(
  leftFilter.value,
  scoreboardStore.scoreboard.leftPlayerId,
  CUSTOM_LEFT_PLAYER_ID,
  scoreboardStore.scoreboard.leftNameOverride,
));

const rightPlayerOptions = computed(() => buildPlayerOptions(
  rightFilter.value,
  scoreboardStore.scoreboard.rightPlayerId,
  CUSTOM_RIGHT_PLAYER_ID,
  scoreboardStore.scoreboard.rightNameOverride,
));

const leftSelectedPlayer = computed(() => playersStore.players[scoreboardStore.scoreboard.leftPlayerId]);
const rightSelectedPlayer = computed(() => playersStore.players[scoreboardStore.scoreboard.rightPlayerId]);

const getPlayerLabel = (playerId: string) => {
  if (playerId === CUSTOM_LEFT_PLAYER_ID) {
    return scoreboardStore.scoreboard.leftNameOverride;
  }
  if (playerId === CUSTOM_RIGHT_PLAYER_ID) {
    return scoreboardStore.scoreboard.rightNameOverride;
  }
  const match = playerOptions.value.find((option) => option.value === playerId);
  return match ? match.label : '';
};

const playerExistsByGamertag = (name: string) => {
  const normalized = normalizeName(name);
  if (!normalized) {
    return false;
  }
  return Object.values(playersStore.players).some((player) => normalizeName(player.gamertag || '') === normalized);
};

const leftDisplayName = computed(() => scoreboardStore.scoreboard.leftNameOverride || getPlayerLabel(scoreboardStore.scoreboard.leftPlayerId));
const rightDisplayName = computed(() => scoreboardStore.scoreboard.rightNameOverride || getPlayerLabel(scoreboardStore.scoreboard.rightPlayerId));

const leftCanSave = computed(
  () => Boolean(scoreboardStore.scoreboard.leftNameOverride.trim())
    && !playerExistsByGamertag(scoreboardStore.scoreboard.leftNameOverride),
);

const rightCanSave = computed(
  () => Boolean(scoreboardStore.scoreboard.rightNameOverride.trim())
    && !playerExistsByGamertag(scoreboardStore.scoreboard.rightNameOverride),
);

const leftTeamChanged = computed(() => {
  const player = leftSelectedPlayer.value;
  if (!player) {
    return false;
  }
  return player.team !== scoreboardStore.scoreboard.leftTeamOverride;
});

const rightTeamChanged = computed(() => {
  const player = rightSelectedPlayer.value;
  if (!player) {
    return false;
  }
  return player.team !== scoreboardStore.scoreboard.rightTeamOverride;
});

const leftCountryChanged = computed(() => {
  const player = leftSelectedPlayer.value;
  if (!player) {
    return false;
  }
  return player.country !== scoreboardStore.scoreboard.leftCountryOverride;
});

const rightCountryChanged = computed(() => {
  const player = rightSelectedPlayer.value;
  if (!player) {
    return false;
  }
  return player.country !== scoreboardStore.scoreboard.rightCountryOverride;
});

const leftPendingGamertag = computed(() => {
  const override = scoreboardStore.scoreboard.leftNameOverride.trim();
  if (override) {
    return override;
  }
  return leftSelectedPlayer.value?.gamertag ?? '';
});

const rightPendingGamertag = computed(() => {
  const override = scoreboardStore.scoreboard.rightNameOverride.trim();
  if (override) {
    return override;
  }
  return rightSelectedPlayer.value?.gamertag ?? '';
});

const leftNameChanged = computed(() => {
  const player = leftSelectedPlayer.value;
  if (!player) {
    return false;
  }
  return player.gamertag !== leftPendingGamertag.value;
});

const rightNameChanged = computed(() => {
  const player = rightSelectedPlayer.value;
  if (!player) {
    return false;
  }
  return player.gamertag !== rightPendingGamertag.value;
});

const leftCanSaveNameChange = computed(
  () => leftNameChanged.value && !playerExistsByGamertag(leftPendingGamertag.value),
);

const rightCanSaveNameChange = computed(
  () => rightNameChanged.value && !playerExistsByGamertag(rightPendingGamertag.value),
);

const leftShowsNameSave = computed(() => leftCanSave.value || leftCanSaveNameChange.value);
const rightShowsNameSave = computed(() => rightCanSave.value || rightCanSaveNameChange.value);

const startLeftCustomPlayer = () => {
  const wasCustom = scoreboardStore.scoreboard.leftPlayerId === CUSTOM_LEFT_PLAYER_ID;
  scoreboardStore.scoreboard.leftPlayerId = CUSTOM_LEFT_PLAYER_ID;
  if (!wasCustom) {
    scoreboardStore.scoreboard.leftTeamOverride = '';
    scoreboardStore.scoreboard.leftCountryOverride = '';
  }
};

const startRightCustomPlayer = () => {
  const wasCustom = scoreboardStore.scoreboard.rightPlayerId === CUSTOM_RIGHT_PLAYER_ID;
  scoreboardStore.scoreboard.rightPlayerId = CUSTOM_RIGHT_PLAYER_ID;
  if (!wasCustom) {
    scoreboardStore.scoreboard.rightTeamOverride = '';
    scoreboardStore.scoreboard.rightCountryOverride = '';
  }
};

const filterPlayerInput = (
  val: string,
  update: (fn: () => void) => void,
  filterValue: Ref<string>,
  focused: Ref<boolean>,
  inputValue: Ref<string>,
  selectedPlayerId: string,
  customPlayerId: string,
  customNameOverride: string,
  setCustomNameOverride: (value: string) => void,
  startCustomPlayer: () => void,
) => {
  update(() => {
    filterValue.value = val;

    if (!focused.value) {
      return;
    }

    if (!val.trim() && selectedPlayerId === customPlayerId) {
      inputValue.value = customNameOverride;
      return;
    }

    inputValue.value = val;
    setCustomNameOverride(val);
    if (val.trim()) {
      startCustomPlayer();
    }
  });
};

const onLeftFilter = (val: string, update: (fn: () => void) => void) => {
  filterPlayerInput(
    val,
    update,
    leftFilter,
    leftFocused,
    leftInput,
    scoreboardStore.scoreboard.leftPlayerId,
    CUSTOM_LEFT_PLAYER_ID,
    scoreboardStore.scoreboard.leftNameOverride,
    (value) => {
      scoreboardStore.scoreboard.leftNameOverride = value;
    },
    startLeftCustomPlayer,
  );
};

const onRightFilter = (val: string, update: (fn: () => void) => void) => {
  filterPlayerInput(
    val,
    update,
    rightFilter,
    rightFocused,
    rightInput,
    scoreboardStore.scoreboard.rightPlayerId,
    CUSTOM_RIGHT_PLAYER_ID,
    scoreboardStore.scoreboard.rightNameOverride,
    (value) => {
      scoreboardStore.scoreboard.rightNameOverride = value;
    },
    startRightCustomPlayer,
  );
};

const onLeftFocus = () => {
  leftFocused.value = true;
  leftInput.value = leftDisplayName.value;
};

const onLeftBlur = () => {
  leftFocused.value = false;
  leftFilter.value = '';
  leftInput.value = leftDisplayName.value;
};

const onRightFocus = () => {
  rightFocused.value = true;
  rightInput.value = rightDisplayName.value;
};

const onRightBlur = () => {
  rightFocused.value = false;
  rightFilter.value = '';
  rightInput.value = rightDisplayName.value;
};

const applyLeftPlayerData = (playerId: string) => {
  const player = playersStore.players[playerId];
  scoreboardStore.scoreboard.leftTeamOverride = player?.team ?? '';
  scoreboardStore.scoreboard.leftCountryOverride = player?.country ?? '';
  leftCountryInput.value = getCountryLabel(scoreboardStore.scoreboard.leftCountryOverride);
};

const applyRightPlayerData = (playerId: string) => {
  const player = playersStore.players[playerId];
  scoreboardStore.scoreboard.rightTeamOverride = player?.team ?? '';
  scoreboardStore.scoreboard.rightCountryOverride = player?.country ?? '';
  rightCountryInput.value = getCountryLabel(scoreboardStore.scoreboard.rightCountryOverride);
};

const onLeftSelect = (playerId: string) => {
  const hasExistingPlayer = Boolean(playerId && playersStore.players[playerId]);
  if (!hasExistingPlayer) {
    return;
  }

  leftFocused.value = false;
  scoreboardStore.scoreboard.leftNameOverride = '';
  leftFilter.value = '';
  leftInput.value = getPlayerLabel(playerId);
  applyLeftPlayerData(playerId);
};

const onRightSelect = (playerId: string) => {
  const hasExistingPlayer = Boolean(playerId && playersStore.players[playerId]);
  if (!hasExistingPlayer) {
    return;
  }

  rightFocused.value = false;
  scoreboardStore.scoreboard.rightNameOverride = '';
  rightFilter.value = '';
  rightInput.value = getPlayerLabel(playerId);
  applyRightPlayerData(playerId);
};

const createPlayerId = (name: string) => {
  const base = name
    .trim()
    .toLowerCase()
    .normalize('NFD')
    .replace(/[^\w\s-]/g, '')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/\s+/g, '-');

  const seed = base || 'player';
  let index = 1;
  let candidate = seed;
  while (playersStore.players[candidate]) {
    index += 1;
    candidate = `${seed}-${index}`;
  }
  return candidate;
};

const saveLeftPlayer = () => {
  const gamertag = scoreboardStore.scoreboard.leftNameOverride.trim();
  if (!gamertag || playerExistsByGamertag(gamertag)) {
    return;
  }
  const id = createPlayerId(gamertag);
  playersStore.upsertPlayer(id, {
    gamertag,
    name: '',
    team: scoreboardStore.scoreboard.leftTeamOverride,
    country: scoreboardStore.scoreboard.leftCountryOverride,
    twitter: '',
  });
  scoreboardStore.scoreboard.leftPlayerId = id;
  scoreboardStore.scoreboard.leftNameOverride = '';
  leftInput.value = gamertag;
};

const saveRightPlayer = () => {
  const gamertag = scoreboardStore.scoreboard.rightNameOverride.trim();
  if (!gamertag || playerExistsByGamertag(gamertag)) {
    return;
  }
  const id = createPlayerId(gamertag);
  playersStore.upsertPlayer(id, {
    gamertag,
    name: '',
    team: scoreboardStore.scoreboard.rightTeamOverride,
    country: scoreboardStore.scoreboard.rightCountryOverride,
    twitter: '',
  });
  scoreboardStore.scoreboard.rightPlayerId = id;
  scoreboardStore.scoreboard.rightNameOverride = '';
  rightInput.value = gamertag;
};

const saveLeftNameChange = () => {
  const playerId = scoreboardStore.scoreboard.leftPlayerId;
  const player = playersStore.players[playerId];
  if (!player) {
    return;
  }
  if (!leftCanSaveNameChange.value) {
    return;
  }
  playersStore.upsertPlayer(playerId, {
    ...player,
    gamertag: leftPendingGamertag.value,
  });
  scoreboardStore.scoreboard.leftNameOverride = '';
};

const saveRightNameChange = () => {
  const playerId = scoreboardStore.scoreboard.rightPlayerId;
  const player = playersStore.players[playerId];
  if (!player) {
    return;
  }
  if (!rightCanSaveNameChange.value) {
    return;
  }
  playersStore.upsertPlayer(playerId, {
    ...player,
    gamertag: rightPendingGamertag.value,
  });
  scoreboardStore.scoreboard.rightNameOverride = '';
};

const saveLeftTeamChange = () => {
  const playerId = scoreboardStore.scoreboard.leftPlayerId;
  const player = playersStore.players[playerId];
  if (!player) {
    return;
  }
  playersStore.upsertPlayer(playerId, {
    ...player,
    team: scoreboardStore.scoreboard.leftTeamOverride,
  });
};

const saveRightTeamChange = () => {
  const playerId = scoreboardStore.scoreboard.rightPlayerId;
  const player = playersStore.players[playerId];
  if (!player) {
    return;
  }
  playersStore.upsertPlayer(playerId, {
    ...player,
    team: scoreboardStore.scoreboard.rightTeamOverride,
  });
};

const saveLeftCountryChange = () => {
  const playerId = scoreboardStore.scoreboard.leftPlayerId;
  const player = playersStore.players[playerId];
  if (!player) {
    return;
  }
  playersStore.upsertPlayer(playerId, {
    ...player,
    country: scoreboardStore.scoreboard.leftCountryOverride,
  });
};

const saveRightCountryChange = () => {
  const playerId = scoreboardStore.scoreboard.rightPlayerId;
  const player = playersStore.players[playerId];
  if (!player) {
    return;
  }
  playersStore.upsertPlayer(playerId, {
    ...player,
    country: scoreboardStore.scoreboard.rightCountryOverride,
  });
};

const onLeftNameSave = () => {
  if (leftCanSave.value) {
    saveLeftPlayer();
    return;
  }
  saveLeftNameChange();
};

const onRightNameSave = () => {
  if (rightCanSave.value) {
    saveRightPlayer();
    return;
  }
  saveRightNameChange();
};



watch(
  () => scoreboardStore.scoreboard.leftPlayerId,
  (playerId) => {
    applyLeftPlayerData(playerId);
  },
  { immediate: true },
);

watch(
  () => scoreboardStore.scoreboard.rightPlayerId,
  (playerId) => {
    applyRightPlayerData(playerId);
  },
  { immediate: true },
);

watch(
  () => scoreboardStore.scoreboard.leftCountryOverride,
  (value) => {
    leftCountryInput.value = getCountryLabel(value);
  },
  { immediate: true },
);

watch(
  () => scoreboardStore.scoreboard.rightCountryOverride,
  (value) => {
    rightCountryInput.value = getCountryLabel(value);
  },
  { immediate: true },
);

watchEffect(() => {
  if (!leftFocused.value) {
    leftInput.value = leftDisplayName.value;
  }
});

watchEffect(() => {
  if (!rightFocused.value) {
    rightInput.value = rightDisplayName.value;
  }
});

</script>

<template>
  <div class="scoreboard-panel">
    <div class="row items-center q-mb-md">
      <div class="text-h4">
        Scoreboard
      </div>
    </div>

    <div class="row q-col-gutter-lg items-start">
      <div class="col-12 col-md-5">
        <QCard
          flat
          bordered
        >
          <QCardSection>
            <div class="text-subtitle1 text-weight-bold">
              Left side
            </div>
          </QCardSection>
          <QSeparator />
          <QCardSection>
            <QSelect
              v-model="scoreboardStore.scoreboard.leftPlayerId"
              v-model:input-value="leftInput"
              :options="leftPlayerOptions"
              label="Player"
              dense
              outlined
              emit-value
              map-options
              use-input
              input-debounce="0"
              hide-selected
              fill-input
              @filter="onLeftFilter"
              @focus="onLeftFocus"
              @blur="onLeftBlur"
              @update:model-value="onLeftSelect"
            >
              <template #append>
                <QBtn
                  v-if="leftShowsNameSave"
                  flat
                  round
                  dense
                  icon="save"
                  color="primary"
                  @click.stop="onLeftNameSave"
                />
              </template>
            </QSelect>
            <QInput
              v-model="scoreboardStore.scoreboard.leftTeamOverride"
              label="Team"
              dense
              outlined
              class="q-mt-sm"
            >
              <template #append>
                <QBtn
                  v-if="leftTeamChanged"
                  flat
                  round
                  dense
                  icon="save"
                  color="primary"
                  @click.stop="saveLeftTeamChange"
                />
              </template>
            </QInput>
            <QSelect
              v-model="scoreboardStore.scoreboard.leftCountryOverride"
              v-model:input-value="leftCountryInput"
              :options="leftCountryOptions"
              option-value="value"
              option-label="label"
              emit-value
              map-options
              use-input
              input-debounce="0"
              hide-selected
              fill-input
              clearable
              label="Country"
              dense
              outlined
              class="q-mt-sm"
              @filter="onLeftCountryFilter"
            >
              <template #append>
                <QBtn
                  v-if="leftCountryChanged"
                  flat
                  round
                  dense
                  icon="save"
                  color="primary"
                  @click.stop="saveLeftCountryChange"
                />
              </template>
            </QSelect>
            <QInput
              v-model.number="scoreboardStore.leftScore"
              type="number"
              label="Score"
              dense
              outlined
              class="q-mt-md"
              min="0"
            />
          </QCardSection>
        </QCard>
      </div>

      <div class="col-12 col-md-2">
        <QCard
          flat
          bordered
        >
          <QCardSection>
            <div class="column items-center q-gutter-sm">
              <div class="row items-center q-gutter-sm">
                <QBtn
                  color="secondary"
                  outline
                  round
                  icon="swap_horiz"
                  @click="scoreboardStore.swapPlayers"
                />
                <QBtn
                  color="secondary"
                  outline
                  round
                  icon="restart_alt"
                  @click="scoreboardStore.resetScores"
                />
              </div>
              <QSelect
                v-model="scoreboardStore.scoreboard.game"
                :options="fightingGameOptions"
                label="Juego"
                dense
                outlined
                emit-value
                map-options
                class="full-width"
              />
            </div>
          </QCardSection>
        </QCard>
      </div>

      <div class="col-12 col-md-5">
        <QCard
          flat
          bordered
        >
          <QCardSection>
            <div class="text-subtitle1 text-weight-bold">
              Right side
            </div>
          </QCardSection>
          <QSeparator />
          <QCardSection>
            <QSelect
              v-model="scoreboardStore.scoreboard.rightPlayerId"
              v-model:input-value="rightInput"
              :options="rightPlayerOptions"
              label="Player"
              dense
              outlined
              emit-value
              map-options
              use-input
              input-debounce="0"
              hide-selected
              fill-input
              @filter="onRightFilter"
              @focus="onRightFocus"
              @blur="onRightBlur"
              @update:model-value="onRightSelect"
            >
              <template #append>
                <QBtn
                  v-if="rightShowsNameSave"
                  flat
                  round
                  dense
                  icon="save"
                  color="primary"
                  @click.stop="onRightNameSave"
                />
              </template>
            </QSelect>
            <QInput
              v-model="scoreboardStore.scoreboard.rightTeamOverride"
              label="Team"
              dense
              outlined
              class="q-mt-sm"
            >
              <template #append>
                <QBtn
                  v-if="rightTeamChanged"
                  flat
                  round
                  dense
                  icon="save"
                  color="primary"
                  @click.stop="saveRightTeamChange"
                />
              </template>
            </QInput>
            <QSelect
              v-model="scoreboardStore.scoreboard.rightCountryOverride"
              v-model:input-value="rightCountryInput"
              :options="rightCountryOptions"
              option-value="value"
              option-label="label"
              emit-value
              map-options
              use-input
              input-debounce="0"
              hide-selected
              fill-input
              clearable
              label="Country"
              dense
              outlined
              class="q-mt-sm"
              @filter="onRightCountryFilter"
            >
              <template #append>
                <QBtn
                  v-if="rightCountryChanged"
                  flat
                  round
                  dense
                  icon="save"
                  color="primary"
                  @click.stop="saveRightCountryChange"
                />
              </template>
            </QSelect>
            <QInput
              v-model.number="scoreboardStore.rightScore"
              type="number"
              label="Score"
              dense
              outlined
              class="q-mt-md"
              min="0"
            />
          </QCardSection>
        </QCard>
      </div>
    </div>
  </div>
</template>

<style scoped>
.scoreboard-panel {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
</style>
