<script lang="ts">
  import { onMount } from 'svelte';
  import PageHeader from '$lib/components/layout/PageHeader.svelte';
  import MonthSelector from '$lib/components/layout/MonthSelector.svelte';
  import CapacityCalendar from '$lib/components/capacity/CapacityCalendar.svelte';
  import CapacitySummary from '$lib/components/capacity/CapacitySummary.svelte';
  import HolidayManager from '$lib/components/capacity/HolidayManager.svelte';
  import PTOManager from '$lib/components/capacity/PTOManager.svelte';
  import CapacityExpertGrid from '$lib/components/capacity/CapacityExpertGrid.svelte';
  import { selectedPeriod } from '$lib/stores/period';
  import { expertMode, setExpertMode } from '$lib/stores/expertMode';
  import {
    holidaysStore,
    loadHolidays,
    loadPTOs,
    loadRevenue,
    loadTeamCapacity,
    ptosStore,
    revenueStore,
    teamCapacityStore
  } from '$lib/stores/capacity';
  import { teamMembersStore } from '$lib/stores/teamMembers';
  import { getIndividualCapacity, saveAvailability } from '$lib/api/capacity';
  import { ApiError, GENERIC_SERVER_ERROR_MESSAGE, sanitizeApiErrorMessage } from '$lib/services/api';
  import type { Capacity } from '$lib/types/capacity';

  type TabKey = 'calendar' | 'summary' | 'holidays' | 'pto';

  const tabs: Array<{ id: TabKey; label: string }> = [
    { id: 'calendar', label: 'Calendar' },
    { id: 'summary', label: 'Summary' },
    { id: 'holidays', label: 'Holidays' },
    { id: 'pto', label: 'PTO' }
  ];

  let activeTab: TabKey = 'calendar';
  let selectedMemberId = '';
  let individualCapacity: Capacity | null = null;
  let loadingIndividual = false;
  let calendarError: string | null = null;
  let availabilitySaving = false;
  let availabilityError: string | null = null;
  let expertDirtyCount = 0;
  let showExpertModeConfirm = false;
  let pendingExpertModeValue = false;

  onMount(async () => {
    try {
      await teamMembersStore.load();
    } catch (error) {
      console.error('Unable to load team members', error);
    }
  });

  function mapError(error: unknown, fallback: string) {
    if (error instanceof ApiError) {
      const sanitized = sanitizeApiErrorMessage(error.message);
      return sanitized === GENERIC_SERVER_ERROR_MESSAGE ? fallback : sanitized;
    }
    if (error instanceof Error && error.message) {
      const sanitized = sanitizeApiErrorMessage(error.message);
      return sanitized === GENERIC_SERVER_ERROR_MESSAGE ? fallback : sanitized;
    }
    return fallback;
  }

  async function refreshIndividualCapacity(memberId: string, period: string, force = false) {
    if (
      !force &&
      individualCapacity &&
      individualCapacity.team_member_id === memberId &&
      individualCapacity.month === period
    ) {
      return;
    }

    loadingIndividual = true;
    calendarError = null;

    try {
      individualCapacity = await getIndividualCapacity(period, memberId);
    } catch (error) {
      console.error('Failed to load capacity details', error, { memberId, period });
      calendarError = mapError(error, 'Unable to load individual capacity data.');
      individualCapacity = null;
    } finally {
      loadingIndividual = false;
    }
  }

  function applyAvailabilityLocally(date: string, availability: number) {
    if (!individualCapacity) {
      return;
    }

    let changed = false;
    const nextDetails = individualCapacity.details.map((detail) => {
      if (detail.date !== date) {
        return detail;
      }

      changed = true;
      return {
        ...detail,
        availability,
        effective_hours: Math.round(availability * 8 * 10) / 10
      };
    });

    if (!changed) {
      return;
    }

    const personDays = nextDetails.reduce((sum, detail) => sum + detail.availability, 0);

    individualCapacity = {
      ...individualCapacity,
      details: nextDetails,
      person_days: Math.round(personDays * 100) / 100,
      hours: Math.round(personDays * 8)
    };
  }

  $: if ($teamMembersStore.length) {
    const exists = $teamMembersStore.some((member) => member.id === selectedMemberId);
    if (!selectedMemberId || !exists) {
      selectedMemberId = $teamMembersStore[0].id;
    }
  }

  async function handleAvailabilityChange(event: CustomEvent<{ date: string; availability: 0 | 0.5 | 1 }>) {
    const { date, availability } = event.detail;
    const period = $selectedPeriod;

    if (!selectedMemberId || !period) {
      return;
    }

    availabilitySaving = true;
    availabilityError = null;

    try {
      await saveAvailability({
        team_member_id: selectedMemberId,
        date,
        availability
      });

      applyAvailabilityLocally(date, availability);

      await Promise.all([
        loadTeamCapacity(period),
        loadRevenue(period)
      ]);
    } catch (error) {
      console.error('Failed to save availability', error, { memberId: selectedMemberId, date, availability });
      availabilityError = mapError(error, 'Unable to save availability changes.');
    } finally {
      availabilitySaving = false;
    }
  }

  function handleTabChange(tabId: TabKey) {
    activeTab = tabId;

    const period = $selectedPeriod;
    if (!period) {
      return;
    }

    if (tabId === 'summary') {
      void Promise.all([loadTeamCapacity(period), loadRevenue(period)]);
      return;
    }

    if (tabId === 'holidays') {
      void loadHolidays(period);
      return;
    }

    if (tabId === 'pto' && selectedMemberId) {
      void loadPTOs(period, selectedMemberId);
      return;
    }

    if (tabId === 'calendar' && selectedMemberId) {
      void refreshIndividualCapacity(selectedMemberId, period, true);
    }
  }

  $: if ($selectedPeriod) {
    loadTeamCapacity($selectedPeriod);
    loadRevenue($selectedPeriod);
    loadHolidays($selectedPeriod);
  }

  $: if ($selectedPeriod && selectedMemberId) {
    loadPTOs($selectedPeriod, selectedMemberId);
    refreshIndividualCapacity(selectedMemberId, $selectedPeriod);
  }

  function handleExpertModeToggle() {
    if ($expertMode && expertDirtyCount > 0) {
      pendingExpertModeValue = false;
      showExpertModeConfirm = true;
    } else {
      setExpertMode(!$expertMode);
    }
  }

  function confirmExpertModeSwitch() {
    setExpertMode(pendingExpertModeValue);
    expertDirtyCount = 0;
    showExpertModeConfirm = false;
  }

  function cancelExpertModeSwitch() {
    showExpertModeConfirm = false;
  }

  function handleExpertCellSaved() {
    expertDirtyCount = 0;
  }
</script>

<svelte:head>
  <title>Capacity Planning | Headroom</title>
</svelte:head>

<section class="space-y-6">
  {#if availabilitySaving}
    <div class="toast toast-top toast-center z-50">
      <div class="alert alert-info shadow-lg text-sm">
        <span class="loading loading-spinner loading-xs"></span>
        <span>Saving availability...</span>
      </div>
    </div>
  {/if}

  <PageHeader title="Capacity Planning" description="Understand availability and possible revenue">
    {#snippet children()}
      <MonthSelector />
    {/snippet}
  </PageHeader>

  <div class="flex items-center justify-between" data-testid="capacity-tabs">
    <div class="tabs relative z-40">
      {#each tabs as tab}
        <button
          class={`tab tab-lg ${tab.id === activeTab ? 'tab-active' : ''}`}
          type="button"
          on:click={() => handleTabChange(tab.id)}
        >
          {tab.label}
        </button>
      {/each}
    </div>

    <label class="hidden md:flex items-center gap-2 cursor-pointer">
      <span class="text-sm font-medium">Expert Mode</span>
      <input
        type="checkbox"
        class="toggle toggle-primary"
        checked={$expertMode}
        on:change={handleExpertModeToggle}
        aria-label="Toggle Expert Mode"
      />
    </label>
  </div>

  <div class="rounded-2xl border border-base-200 bg-base-100 p-6 shadow-sm">
    {#if $expertMode && activeTab === 'calendar'}
      <CapacityExpertGrid
        month={$selectedPeriod}
        teamMembers={$teamMembersStore.filter((m) => m.active)}
        holidays={$holidaysStore}
        on:dirty={(e) => {
          expertDirtyCount = e.detail.count;
        }}
        on:saved={handleExpertCellSaved}
      />
    {:else if activeTab === 'calendar'}
      <div class="space-y-4">
        <div class="flex flex-wrap items-center gap-3">
          <label class="text-sm font-semibold">Team member</label>
          <select
            class="select select-sm"
            bind:value={selectedMemberId}
            aria-label="Select team member"
          >
            {#each $teamMembersStore as member}
              <option value={member.id}>{member.name}</option>
            {/each}
          </select>
        </div>

        {#if calendarError}
          <div class="alert alert-error text-sm">{calendarError}</div>
        {/if}

        {#if availabilityError}
          <div class="alert alert-error text-sm">{availabilityError}</div>
        {/if}

        {#if !selectedMemberId}
          <p class="text-sm text-base-content/60">Select a team member to view the calendar.</p>
        {:else if loadingIndividual}
          <div class="flex items-center gap-2 text-sm text-base-content/60">
            <span class="loading loading-spinner loading-sm"></span>
            Loading capacity details...
          </div>
        {:else}
          <CapacityCalendar
            month={$selectedPeriod}
            capacity={individualCapacity}
            holidays={$holidaysStore}
            ptos={$ptosStore}
            on:availabilitychange={handleAvailabilityChange}
          />
        {/if}
      </div>
    {:else if activeTab === 'summary'}
      <CapacitySummary
        teamCapacity={$teamCapacityStore}
        revenue={$revenueStore}
        teamMembers={$teamMembersStore}
      />
    {:else if activeTab === 'holidays'}
      <HolidayManager month={$selectedPeriod} holidays={$holidaysStore} />
    {:else}
      <PTOManager
        teamMembers={$teamMembersStore}
        month={$selectedPeriod}
        bind:selectedMemberId={selectedMemberId}
      />
    {/if}
  </div>

  {#if showExpertModeConfirm}
    <dialog class="modal modal-open">
      <div class="modal-box">
        <h3 class="font-bold text-lg mb-4">Unsaved Changes</h3>
        <p>You have unsaved changes in Expert Mode. Discard and switch?</p>
        <div class="modal-action">
          <button class="btn btn-ghost" on:click={cancelExpertModeSwitch}>Cancel</button>
          <button class="btn btn-primary" on:click={confirmExpertModeSwitch}>Discard & Switch</button>
        </div>
      </div>
      <form method="dialog" class="modal-backdrop">
        <button on:click={cancelExpertModeSwitch}>close</button>
      </form>
    </dialog>
  {/if}
</section>
