import { useState, useMemo } from 'react';
import {
  Folder,
  Circle,
  ChevronRight,
  ChevronDown,
  Plus,
  MoreHorizontal,
  Edit2,
  Archive,
  ArchiveRestore,
  Trash2,
  Search,
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { trpc } from '@/lib/trpc';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Switch } from '@/components/ui/switch';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from '@/components/ui/collapsible';
import {
  Empty,
  EmptyContent,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
} from '@/components/ui/empty';

const NO_CLIENT_KEY = '__no_client__';

type ProjectSidebarProps = {
  selectedProjectId: string | undefined;
  onSelectProject: (id: string) => void;
};

export function ProjectSidebar({ selectedProjectId, onSelectProject }: ProjectSidebarProps) {
  const utils = trpc.useUtils();

  const [showArchived, setShowArchived] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');
  const [expanded, setExpanded] = useState<Set<string>>(new Set());
  const [deleteProjectId, setDeleteProjectId] = useState<{ id: string; name: string } | null>(null);
  const [editDialog, setEditDialog] = useState<{ id: string; name: string; clientId: string | null } | null>(null);
  const [editClientValue, setEditClientValue] = useState<string>(NO_CLIENT_KEY);

  // New-project dialog state
  const [newProjectOpen, setNewProjectOpen] = useState(false);
  const [newProjectName, setNewProjectName] = useState('');
  const [newProjectClientId, setNewProjectClientId] = useState<string>(NO_CLIENT_KEY);
  const [newProjectSubClientId, setNewProjectSubClientId] = useState<string>(NO_CLIENT_KEY);
  // Inline client creation
  const [creatingClient, setCreatingClient] = useState(false);
  const [newClientName, setNewClientName] = useState('');
  // Inline sub-client creation
  const [creatingSubClient, setCreatingSubClient] = useState(false);
  const [newSubClientName, setNewSubClientName] = useState('');

  const { data: projectList = [] } = trpc.projects.list.useQuery(
    { includeArchived: showArchived },
  );
  const { data: clientList = [] } = trpc.clients.list.useQuery();

  // Derived: top-level clients and sub-clients grouped by parentId
  const topLevelClients = useMemo(
    () => clientList.filter((c) => !c.parentId),
    [clientList],
  );
  const subClientsByParent = useMemo(() => {
    const m = new Map<string, typeof clientList>();
    for (const c of clientList) {
      if (c.parentId) {
        const arr = m.get(c.parentId);
        if (arr) arr.push(c);
        else m.set(c.parentId, [c]);
      }
    }
    return m;
  }, [clientList]);

  const createClientMutation = trpc.clients.create.useMutation({
    onSuccess: () => {
      void utils.clients.list.invalidate();
    },
  });

  const createMutation = trpc.projects.create.useMutation({
    onSuccess: (data, variables) => {
      // Auto-expand the matching client group
      const groupKey = variables.clientId ?? NO_CLIENT_KEY;
      setExpanded((prev) => new Set([...prev, groupKey]));
      onSelectProject(data.id);
      void utils.projects.list.invalidate();
    },
  });

  const updateMutation = trpc.projects.update.useMutation({
    onSuccess: () => { void utils.projects.list.invalidate(); },
  });

  const deleteMutation = trpc.projects.delete.useMutation({
    onSuccess: () => {
      setDeleteProjectId(null);
      void utils.projects.list.invalidate();
    },
  });

  // Build a client lookup map
  const clientMap = useMemo(() => {
    const m = new Map<string, string>();
    for (const c of clientList) m.set(c.id, c.name);
    return m;
  }, [clientList]);

  // Group projects by clientId, filter by search
  const grouped = useMemo(() => {
    const lowerSearch = searchQuery.toLowerCase();
    const filtered = projectList.filter((p) =>
      !searchQuery || p.name.toLowerCase().includes(lowerSearch),
    );

    const groups = new Map<string, typeof filtered>();
    for (const p of filtered) {
      const key = p.clientId ?? NO_CLIENT_KEY;
      const arr = groups.get(key);
      if (arr) arr.push(p);
      else groups.set(key, [p]);
    }
    return groups;
  }, [projectList, searchQuery]);

  // Auto-expand all groups when searching
  const effectiveExpanded = useMemo(() => {
    if (searchQuery) {
      return new Set([...grouped.keys()]);
    }
    return expanded;
  }, [searchQuery, grouped, expanded]);

  function toggleExpanded(key: string) {
    setExpanded((prev) => {
      const next = new Set(prev);
      next.has(key) ? next.delete(key) : next.add(key);
      return next;
    });
  }

  function handleOpenNewProject() {
    setNewProjectName('');
    setNewProjectClientId(NO_CLIENT_KEY);
    setNewProjectSubClientId(NO_CLIENT_KEY);
    setCreatingClient(false);
    setNewClientName('');
    setCreatingSubClient(false);
    setNewSubClientName('');
    setNewProjectOpen(true);
  }

  async function handleCreateProject() {
    const name = newProjectName.trim();
    if (!name) return;

    let resolvedClientId: string | undefined;

    // If creating a brand-new client first
    if (creatingClient && newClientName.trim()) {
      const result = await createClientMutation.mutateAsync({ name: newClientName.trim() });
      resolvedClientId = result.id;

      // If also creating a sub-client under the new client
      if (creatingSubClient && newSubClientName.trim()) {
        const subResult = await createClientMutation.mutateAsync({
          name: newSubClientName.trim(),
          parentId: resolvedClientId,
        });
        resolvedClientId = subResult.id;
      }
    } else if (newProjectClientId !== NO_CLIENT_KEY) {
      // User picked an existing client
      if (creatingSubClient && newSubClientName.trim()) {
        // Create a new sub-client under the selected client
        const subResult = await createClientMutation.mutateAsync({
          name: newSubClientName.trim(),
          parentId: newProjectClientId,
        });
        resolvedClientId = subResult.id;
      } else if (newProjectSubClientId !== NO_CLIENT_KEY) {
        // User picked an existing sub-client
        resolvedClientId = newProjectSubClientId;
      } else {
        // Just the parent client, no sub-client
        resolvedClientId = newProjectClientId;
      }
    }

    createMutation.mutate(
      { name, clientId: resolvedClientId },
      { onSuccess: () => setNewProjectOpen(false) },
    );
  }

  function handleArchiveToggle(id: string, currentStatus: string | null) {
    const newStatus = currentStatus === 'archived' ? 'active' : 'archived';
    updateMutation.mutate({ id, status: newStatus as 'active' | 'archived' });
  }

  function handleEditOpen(project: { id: string; name: string; clientId: string | null }) {
    setEditDialog(project);
    setEditClientValue(project.clientId ?? NO_CLIENT_KEY);
  }

  function handleEditSave() {
    if (!editDialog) return;
    const newClientId = editClientValue === NO_CLIENT_KEY ? null : editClientValue;
    updateMutation.mutate(
      { id: editDialog.id, clientId: newClientId },
      { onSuccess: () => setEditDialog(null) },
    );
  }


  // Sort groups: client groups first (alphabetically), then "Internal / No Client" last
  const sortedGroupKeys = useMemo(() => {
    const keys = [...grouped.keys()];
    return keys.sort((a, b) => {
      if (a === NO_CLIENT_KEY) return 1;
      if (b === NO_CLIENT_KEY) return -1;
      const nameA = clientMap.get(a) ?? '';
      const nameB = clientMap.get(b) ?? '';
      return nameA.localeCompare(nameB);
    });
  }, [grouped, clientMap]);

  const totalProjects = projectList.length;

  return (
    <div className="flex flex-col h-full border-r border-border w-60 shrink-0">
      {/* Header */}
      <div className="flex items-center justify-between px-3 py-2.5 shrink-0">
        <h4 className="text-lg font-semibold text-foreground">Projects</h4>
        <Button
          variant="outline"
          size="icon"
          onClick={handleOpenNewProject}
          disabled={createMutation.isPending}
          aria-label="New Project"
        >
          <Plus />
        </Button>
      </div>

      {/* Search */}
      <div className="px-3 pb-2 shrink-0">
        <div className="relative">
          <Search className="absolute left-2 top-1/2 -translate-y-1/2 size-3.5 text-muted-foreground" />
          <Input
            placeholder="Search projects..."
            className="h-7 text-sm pl-7"
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
          />
        </div>
      </div>

      {/* Show archived toggle */}
      <div className="flex items-center justify-between px-3 pb-2 shrink-0">
        <label htmlFor="show-archived" className="text-xs text-muted-foreground cursor-pointer">
          Show archived
        </label>
        <Switch
          id="show-archived"
          checked={showArchived}
          onCheckedChange={setShowArchived}
          className="scale-75"
        />
      </div>

      {/* Project tree */}
      <div className="flex-1 overflow-y-auto py-1 px-1">
        {totalProjects === 0 ? (
          <Empty>
            <EmptyHeader>
              <EmptyMedia variant="icon">
                <Folder />
              </EmptyMedia>
              <EmptyTitle>No projects yet</EmptyTitle>
              <EmptyDescription>
                Get started by adding your first project.
              </EmptyDescription>
            </EmptyHeader>
            <EmptyContent>
              <Button
                variant="outline"
                size="sm"
                onClick={handleOpenNewProject}
                disabled={createMutation.isPending}
              >
                <Plus className="mr-1 h-4 w-4" />
                Add Project
              </Button>
            </EmptyContent>
          </Empty>
        ) : sortedGroupKeys.length === 0 ? (
          <div className="text-xs text-muted-foreground px-3 py-4 text-center">
            No projects match your search.
          </div>
        ) : (
          sortedGroupKeys.map((groupKey) => {
            const groupProjects = grouped.get(groupKey) ?? [];
            const groupName = groupKey === NO_CLIENT_KEY
              ? 'Internal / No Client'
              : clientMap.get(groupKey) ?? 'Unknown Client';
            const isOpen = effectiveExpanded.has(groupKey);

            return (
              <Collapsible
                key={groupKey}
                open={isOpen}
                onOpenChange={() => toggleExpanded(groupKey)}
              >
                {/* Client group header */}
                <CollapsibleTrigger asChild>
                  <div className="flex items-center h-7 rounded-md text-sm cursor-pointer hover:bg-accent transition-colors px-2">
                    {isOpen ? (
                      <ChevronDown className="size-3 shrink-0 text-muted-foreground mr-1" />
                    ) : (
                      <ChevronRight className="size-3 shrink-0 text-muted-foreground mr-1" />
                    )}
                    <Folder className="size-3.5 shrink-0 text-muted-foreground mr-1.5" />
                    <span className="flex-1 min-w-0 truncate font-medium text-foreground">
                      {groupName}
                    </span>
                    <span className="text-xs text-muted-foreground ml-1">
                      {groupProjects.length}
                    </span>
                  </div>
                </CollapsibleTrigger>

                <CollapsibleContent>
                  {groupProjects.map((project) => (
                    <div
                      key={project.id}
                      className={cn(
                        'group flex items-center h-7 rounded-md text-sm cursor-pointer hover:bg-accent transition-colors',
                        selectedProjectId === project.id && 'bg-sidebar-accent',
                        project.status === 'archived' && 'opacity-60',
                      )}
                      style={{ paddingLeft: '28px', paddingRight: '4px' }}
                      onClick={() => onSelectProject(project.id)}
                    >
                      <Circle className="size-2.5 shrink-0 text-muted-foreground mr-1.5" />
                      <span className="flex-1 min-w-0 truncate text-foreground">
                        {project.name}
                      </span>

                      {/* Context menu */}
                      <DropdownMenu>
                        <DropdownMenuTrigger asChild>
                          <Button
                            variant="ghost"
                            className={cn(
                              'relative z-10 h-5 w-5 min-h-0 min-w-0 p-0 ml-1 text-muted-foreground hover:bg-muted shrink-0',
                              'opacity-0 group-hover:opacity-100 data-[state=open]:opacity-100',
                            )}
                            tabIndex={-1}
                            onClick={(e) => e.stopPropagation()}
                          >
                            <MoreHorizontal className="size-3" />
                          </Button>
                        </DropdownMenuTrigger>
                        <DropdownMenuContent align="end" className="min-w-[152px]">
                          <DropdownMenuItem
                            onClick={(e) => {
                              e.stopPropagation();
                              handleEditOpen({
                                id: project.id,
                                name: project.name,
                                clientId: project.clientId,
                              });
                            }}
                          >
                            <Edit2 />
                            Edit Client
                          </DropdownMenuItem>
                          <DropdownMenuItem
                            onClick={(e) => {
                              e.stopPropagation();
                              handleArchiveToggle(project.id, project.status);
                            }}
                          >
                            {project.status === 'archived' ? (
                              <>
                                <ArchiveRestore />
                                Unarchive
                              </>
                            ) : (
                              <>
                                <Archive />
                                Archive
                              </>
                            )}
                          </DropdownMenuItem>
                          <DropdownMenuSeparator />
                          <DropdownMenuItem
                            variant="destructive"
                            onClick={(e) => {
                              e.stopPropagation();
                              setDeleteProjectId({ id: project.id, name: project.name });
                            }}
                          >
                            <Trash2 />
                            Delete
                          </DropdownMenuItem>
                        </DropdownMenuContent>
                      </DropdownMenu>
                    </div>
                  ))}
                </CollapsibleContent>
              </Collapsible>
            );
          })
        )}
      </div>

      {/* Delete confirmation */}
      <AlertDialog
        open={!!deleteProjectId}
        onOpenChange={(open) => {
          if (!open && !deleteMutation.isPending) setDeleteProjectId(null);
        }}
      >
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>
              Delete &ldquo;{deleteProjectId?.name}&rdquo;?
            </AlertDialogTitle>
            <AlertDialogDescription>
              This will delete the project. Tasks assigned to this project will become unassigned. This action cannot be undone.
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel disabled={deleteMutation.isPending}>Cancel</AlertDialogCancel>
            <AlertDialogAction
              className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
              onClick={() => {
                if (deleteProjectId) deleteMutation.mutate({ id: deleteProjectId.id });
              }}
              disabled={deleteMutation.isPending}
            >
              {deleteMutation.isPending ? 'Deleting\u2026' : 'Delete'}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      {/* New Project dialog */}
      <Dialog open={newProjectOpen} onOpenChange={setNewProjectOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>New Project</DialogTitle>
            <DialogDescription>
              Give your project a name and optionally assign it to a client.
            </DialogDescription>
          </DialogHeader>

          <div className="flex flex-col gap-4 py-2">
            {/* Project name */}
            <div className="flex flex-col gap-1.5">
              <label htmlFor="new-project-name" className="text-sm font-medium">Project Name</label>
              <Input
                id="new-project-name"
                placeholder="e.g. Website Redesign"
                value={newProjectName}
                onChange={(e) => setNewProjectName(e.target.value)}
                autoFocus
              />
            </div>

            {/* Client selection */}
            <div className="flex flex-col gap-1.5">
              <label className="text-sm font-medium">Client <span className="text-muted-foreground font-normal">(optional)</span></label>
              {creatingClient ? (
                <div className="flex items-center gap-2">
                  <Input
                    placeholder="New client name"
                    value={newClientName}
                    onChange={(e) => setNewClientName(e.target.value)}
                    className="flex-1"
                  />
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => {
                      setCreatingClient(false);
                      setNewClientName('');
                      setCreatingSubClient(false);
                      setNewSubClientName('');
                    }}
                  >
                    Cancel
                  </Button>
                </div>
              ) : (
                <div className="flex items-center gap-2">
                  <Select
                    value={newProjectClientId}
                    onValueChange={(v) => {
                      setNewProjectClientId(v);
                      setNewProjectSubClientId(NO_CLIENT_KEY);
                      setCreatingSubClient(false);
                      setNewSubClientName('');
                    }}
                  >
                    <SelectTrigger className="flex-1">
                      <SelectValue placeholder="Select a client" />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value={NO_CLIENT_KEY}>None (Internal)</SelectItem>
                      {topLevelClients.map((c) => (
                        <SelectItem key={c.id} value={c.id}>{c.name}</SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                  <Button
                    variant="outline"
                    size="sm"
                    onClick={() => setCreatingClient(true)}
                  >
                    <Plus className="size-3.5 mr-1" />New
                  </Button>
                </div>
              )}
            </div>

            {/* Sub-client selection — only when a client is selected or being created */}
            {(newProjectClientId !== NO_CLIENT_KEY || (creatingClient && newClientName.trim())) && (
              <div className="flex flex-col gap-1.5">
                <label className="text-sm font-medium">Sub-client <span className="text-muted-foreground font-normal">(optional)</span></label>
                {creatingSubClient ? (
                  <div className="flex items-center gap-2">
                    <Input
                      placeholder="New sub-client name"
                      value={newSubClientName}
                      onChange={(e) => setNewSubClientName(e.target.value)}
                      className="flex-1"
                    />
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => {
                        setCreatingSubClient(false);
                        setNewSubClientName('');
                      }}
                    >
                      Cancel
                    </Button>
                  </div>
                ) : creatingClient ? (
                  /* When creating a new client there are no existing sub-clients to pick */
                  <Button
                    variant="outline"
                    size="sm"
                    className="w-fit"
                    onClick={() => setCreatingSubClient(true)}
                  >
                    <Plus className="size-3.5 mr-1" />New Sub-client
                  </Button>
                ) : (
                  <div className="flex items-center gap-2">
                    <Select
                      value={newProjectSubClientId}
                      onValueChange={setNewProjectSubClientId}
                    >
                      <SelectTrigger className="flex-1">
                        <SelectValue placeholder="Select a sub-client" />
                      </SelectTrigger>
                      <SelectContent>
                        <SelectItem value={NO_CLIENT_KEY}>None</SelectItem>
                        {(subClientsByParent.get(newProjectClientId) ?? []).map((sc) => (
                          <SelectItem key={sc.id} value={sc.id}>{sc.name}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                    <Button
                      variant="outline"
                      size="sm"
                      onClick={() => setCreatingSubClient(true)}
                    >
                      <Plus className="size-3.5 mr-1" />New
                    </Button>
                  </div>
                )}
              </div>
            )}
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={() => setNewProjectOpen(false)}>Cancel</Button>
            <Button
              onClick={handleCreateProject}
              disabled={!newProjectName.trim() || createMutation.isPending || createClientMutation.isPending}
            >
              {createMutation.isPending || createClientMutation.isPending ? 'Creating…' : 'Create Project'}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Edit client dialog */}
      <Dialog
        open={!!editDialog}
        onOpenChange={(open) => {
          if (!open) setEditDialog(null);
        }}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Edit Project Client</DialogTitle>
            <DialogDescription>
              Assign &ldquo;{editDialog?.name}&rdquo; to a client or leave as internal.
            </DialogDescription>
          </DialogHeader>
          <Select value={editClientValue} onValueChange={setEditClientValue}>
            <SelectTrigger>
              <SelectValue placeholder="Select a client" />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value={NO_CLIENT_KEY}>No Client (Internal)</SelectItem>
              {clientList.map((c) => (
                <SelectItem key={c.id} value={c.id}>
                  {c.name}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
          <DialogFooter>
            <Button variant="outline" onClick={() => setEditDialog(null)}>
              Cancel
            </Button>
            <Button onClick={handleEditSave} disabled={updateMutation.isPending}>
              {updateMutation.isPending ? 'Saving\u2026' : 'Save'}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
