<script lang="ts">
  import { onMount } from 'svelte';
  import PageHeader from '$lib/components/layout/PageHeader.svelte';
  import DataTable from '$lib/components/common/DataTable.svelte';
  import FilterBar from '$lib/components/common/FilterBar.svelte';
  import LoadingState from '$lib/components/common/LoadingState.svelte';
  import EmptyState from '$lib/components/common/EmptyState.svelte';
  import { Plus, X, AlertCircle } from 'lucide-svelte';
  import { projectService, type Project, type ProjectType, type ProjectStatus } from '$lib/services/projectService';
  import type { ColumnDef } from '@tanstack/table-core';

  const STATUS_BADGES: Record<string, string> = {
    'Pre-sales': 'badge-ghost',
    'SOW Approval': 'badge-info',
    Estimation: 'badge-info',
    'Estimate Approved': 'badge-success',
    'Resource Allocation': 'badge-info',
    'Sprint 0': 'badge-warning',
    'In Progress': 'badge-primary',
    UAT: 'badge-primary',
    'Handover / Sign-off': 'badge-warning',
    'Estimate Rework': 'badge-warning',
    'On Hold': 'badge-warning',
    Cancelled: 'badge-error',
    Closed: 'badge-success'
  };

  interface ProjectFormState {
    code: string;
    title: string;
    type_id: number;
    status_id?: number;
    approved_estimate: number | null;
  }

  let data = $state<Project[]>([]);
  let loading = $state(true);
  let error = $state<string | null>(null);
  let search = $state('');
  let statusFilter = $state<'all' | string>('all');
  let typeFilter = $state<'all' | string>('all');
  let showModal = $state(false);
  let editingProject = $state<Project | null>(null);
  let formLoading = $state(false);
  let formError = $state<string | null>(null);
  let types = $state<ProjectType[]>([]);
  let statuses = $state<ProjectStatus[]>([]);
  let formData = $state<ProjectFormState>({
    code: '',
    title: '',
    type_id: 0,
    status_id: undefined,
    approved_estimate: null
  });

  const columns: ColumnDef<Project>[] = [
    { accessorKey: 'code', header: 'Code' },
    { accessorKey: 'title', header: 'Title' },
    {
      accessorKey: 'status',
      header: 'Status',
      cell: (info) =>
        info.row.original.status
          ? getStatusBadge(info.row.original.status.name)
          : '-'
    },
    {
      accessorKey: 'type',
      header: 'Type',
      cell: (info) => info.row.original.type?.name ?? '-'
    },
    {
      accessorKey: 'approved_estimate',
      header: 'Approved Estimate',
      cell: (info) => formatEstimate(info.row.original.approved_estimate)
    }
  ];

  onMount(async () => {
    await Promise.all([loadProjects(), loadTypes(), loadStatuses()]);
  });

  async function loadProjects() {
    try {
      loading = true;
      error = null;
      data = await projectService.getAll();
    } catch (err) {
      error = extractErrorMessage(err, 'Failed to load projects');
      console.error('Error loading projects:', err);
    } finally {
      loading = false;
    }
  }

  async function loadTypes() {
    try {
      types = await projectService.getTypes();
      if (types.length && formData.type_id === 0) {
        formData = { ...formData, type_id: types[0].id };
      }
    } catch (err) {
      console.error('Error loading project types:', err);
    }
  }

  async function loadStatuses() {
    try {
      statuses = await projectService.getStatuses();
      if (statuses.length && formData.status_id === undefined) {
        formData = { ...formData, status_id: statuses[0].id };
      }
    } catch (err) {
      console.error('Error loading project statuses:', err);
    }
  }

  function handleCreate() {
    const defaultType = types[0];
    const defaultStatus = statuses[0];
    editingProject = null;
    formData = {
      code: '',
      title: '',
      type_id: defaultType?.id ?? 0,
      status_id: defaultStatus?.id,
      approved_estimate: null
    };
    formError = null;
    showModal = true;
  }

  function handleEdit(project: Project) {
    editingProject = project;
    // Use scalar IDs from API response, fallback to nested objects for backward compatibility
    const typeId = project.type_id ?? project.type?.id ?? 0;
    const statusId = project.status_id ?? project.status?.id;
    formData = {
      code: project.code,
      title: project.title,
      type_id: typeId,
      status_id: statusId,
      approved_estimate: project.approved_estimate ? parseFloat(String(project.approved_estimate)) : null
    };
    formError = null;
    showModal = true;
  }

  async function handleSubmit() {
    if (!formData.code.trim() || !formData.title.trim() || !formData.type_id) {
      formError = 'Code, title, and type are required.';
      return;
    }

    try {
      formLoading = true;
      formError = null;

      if (editingProject) {
        // Update basic info including status and estimate
        await projectService.update(editingProject.id, {
          code: formData.code,
          title: formData.title,
          type_id: formData.type_id,
          status_id: formData.status_id,
          approved_estimate: formData.approved_estimate
        });
      } else {
        await projectService.create({
          code: formData.code,
          title: formData.title,
          type_id: formData.type_id
        });
      }

      await loadProjects();
      closeModal();
    } catch (err) {
      const message = extractErrorMessage(err);
      console.error('Project form error:', err);
      if (message.toLowerCase().includes('unique')) {
        formError = 'Project code must be unique.';
      } else if (message.toLowerCase().includes('cannot transition')) {
        formError = message;
      } else {
        formError = message;
      }
    } finally {
      formLoading = false;
    }
  }

  function closeModal() {
    showModal = false;
    editingProject = null;
    formError = null;
  }

  function extractErrorMessage(error: unknown, fallback = 'An error occurred') {
    if (error instanceof Error) {
      return error.message;
    }
    if (typeof error === 'object' && error !== null && 'data' in error) {
      const err = error as { data: Record<string, string[]>; message?: string };
      if (err.data?.errors) {
        return Object.values(err.data.errors)
          .flat()
          .join('; ');
      }
      if (err.message) {
        return err.message;
      }
    }
    return fallback;
  }

  function getStatusBadge(name?: string) {
    if (!name) return '<span class="badge badge-sm badge-outline">-</span>';
    const badgeClass = STATUS_BADGES[name] ?? 'badge-outline';
    return `<span class="badge ${badgeClass} badge-sm">${name}</span>`;
  }

  function formatEstimate(value: number | string | null | undefined) {
    if (value == null) return '-';
    const num = typeof value === 'string' ? parseFloat(value) : value;
    if (isNaN(num)) return '-';
    return num.toLocaleString(undefined, {
      minimumFractionDigits: 0,
      maximumFractionDigits: 2
    });
  }

  function handleTypeChange(event: Event) {
    const target = event.target as HTMLSelectElement;
    formData.type_id = Number(target.value);
  }

  function handleStatusChange(event: Event) {
    const target = event.target as HTMLSelectElement;
    formData.status_id = Number(target.value);
  }

  function handleEstimateInput(event: Event) {
    const target = event.target as HTMLInputElement;
    const value = target.value;
    formData.approved_estimate = value ? Number(value) : null;
  }

  function handleBackdropKeydown(event: KeyboardEvent) {
    if (event.key === 'Escape') {
      closeModal();
    }
  }

  let filteredData = $derived(data.filter((project) => {
    const searchTerm = search.toLowerCase();
    const matchesSearch =
      project.title.toLowerCase().includes(searchTerm) ||
      project.code.toLowerCase().includes(searchTerm);
    const matchesStatus =
      statusFilter === 'all' || project.status?.name === statusFilter;
    const matchesType = typeFilter === 'all' || project.type?.name === typeFilter;
    return matchesSearch && matchesStatus && matchesType;
  }));
</script>

<svelte:head>
  <title>Projects | Headroom</title>
</svelte:head>

<PageHeader title="Projects" description="Manage project lifecycle">
  {#snippet children()}
    <button class="btn btn-primary btn-sm gap-2" onclick={handleCreate}>
      <Plus size={16} />
      New Project
    </button>
  {/snippet}
</PageHeader>

<FilterBar
  searchValue={search}
  searchPlaceholder="Search projects..."
  onSearchChange={(value) => (search = value)}
>
  {#snippet children()}
    <select class="select select-sm" bind:value={statusFilter}>
      <option value="all">All Status</option>
      {#each statuses as status}
        <option value={status.name}>{status.name}</option>
      {/each}
    </select>
    <select class="select select-sm" bind:value={typeFilter}>
      <option value="all">All Types</option>
      {#each types as type}
        <option value={type.name}>{type.name}</option>
      {/each}
    </select>
  {/snippet}
</FilterBar>

{#if loading}
  <LoadingState />
{:else if error}
  <div class="alert alert-error">
    <AlertCircle size={20} />
    <span>{error}</span>
  </div>
{:else if data.length === 0}
  <EmptyState
    title="No projects"
    description="Create your first project to get started."
  >
    {#snippet children()}
      <button class="btn btn-primary" onclick={handleCreate}>
        <Plus size={16} />
        New Project
      </button>
    {/snippet}
  </EmptyState>
{:else}
  <DataTable
    data={filteredData}
    {columns}
    {loading}
    emptyTitle="No matching projects"
    emptyDescription="Try adjusting your search or filter."
    onRowClick={handleEdit}
  />
{/if}

{#if showModal}
  <div class="modal modal-open">
    <div class="modal-box max-w-xl">
      <div class="flex justify-between items-center mb-4">
        <h3 class="font-bold text-lg">
          {editingProject ? 'Edit Project' : 'New Project'}
        </h3>
        <button class="btn btn-ghost btn-sm btn-circle" onclick={closeModal} aria-label="Close">
          <X size={18} />
        </button>
      </div>

      {#if formError}
        <div class="alert alert-error mb-4 text-sm">
          <AlertCircle size={16} />
          <span class="ml-2">{formError}</span>
        </div>
      {/if}

      <form onsubmit={(event) => { event.preventDefault(); handleSubmit(); }}>
        <div class="form-control mb-4 flex flex-row items-center gap-4">
          <label class="label w-28 shrink-0" for="project-code">
            <span class="label-text font-medium">Code</span>
          </label>
          <input
            id="project-code"
            name="code"
            class="input input-bordered flex-1"
            type="text"
            bind:value={formData.code}
            placeholder="Enter project code"
            required
          />
        </div>

        <div class="form-control mb-4 flex flex-row items-center gap-4">
          <label class="label w-28 shrink-0" for="project-title">
            <span class="label-text font-medium">Title</span>
          </label>
          <input
            id="project-title"
            name="title"
            class="input input-bordered flex-1"
            type="text"
            bind:value={formData.title}
            placeholder="Enter project title"
            required
          />
        </div>

        <div class="form-control mb-4 flex flex-row items-center gap-4">
          <label class="label w-28 shrink-0" for="project-type">
            <span class="label-text font-medium">Type</span>
          </label>
          <select
            id="project-type"
            name="type_id"
            class="select select-bordered flex-1"
            onchange={handleTypeChange}
            value={formData.type_id}
            required
          >
            {#each types as type}
              <option value={type.id}>{type.name}</option>
            {/each}
          </select>
        </div>

        {#if editingProject}
          <div class="form-control mb-4 flex flex-row items-center gap-4">
            <label class="label w-28 shrink-0" for="project-status">
              <span class="label-text font-medium">Status</span>
            </label>
            <select
              id="project-status"
              name="status_id"
              class="select select-bordered flex-1"
              onchange={handleStatusChange}
              value={formData.status_id}
              required
            >
              {#each statuses as status}
                <option value={status.id}>{status.name}</option>
              {/each}
            </select>
          </div>

          <div class="form-control mb-6 flex flex-row items-center gap-4">
            <label class="label w-40 shrink-0" for="approved-estimate">
              <span class="label-text font-medium">Approved Estimate</span>
            </label>
            <input
              id="approved-estimate"
              name="approved_estimate"
              class="input input-bordered flex-1"
              type="number"
              min="0"
              step="0.01"
              value={formData.approved_estimate ?? ''}
              oninput={handleEstimateInput}
            />
          </div>
        {/if}

        <div class="modal-action">
          <button type="button" class="btn btn-ghost" onclick={closeModal}>
            Cancel
          </button>
          <button type="submit" class="btn btn-primary" disabled={formLoading}>
            {#if formLoading}
              <span class="loading loading-spinner loading-sm"></span>
            {/if}
            {editingProject ? 'Update' : 'Create'}
          </button>
        </div>
      </form>
    </div>
    <div
      class="modal-backdrop"
      onclick={closeModal}
      onkeydown={handleBackdropKeydown}
      role="button"
      tabindex="-1"
    ></div>
  </div>
{/if}
