"use client";

import { useMemo, useState } from "react";
import { useTranslations } from "next-intl";
import { ChevronDown, ChevronRight, Globe, ListTodo, Pencil, RefreshCw, Share2, Trash2, Cake, User, Users, Plus, Eraser, Palette, Shuffle } from "lucide-react";
import { cn, formatDateTime } from "@/lib/utils";
import type { Calendar } from "@/lib/jmap/types";
import { CalendarColorPicker } from "@/components/settings/calendar-management-settings";
import { useCalendarStore } from "@/stores/calendar-store";
import { useSettingsStore } from "@/stores/settings-store";
import { useTaskStore } from "@/stores/task-store";
import { useAccountStore } from "@/stores/account-store";
import { BIRTHDAY_CALENDAR_ID } from "@/lib/birthday-calendar";
import { sharedCalendarColorKey } from "@/lib/shared-calendar-colors";
import { toast } from "@/stores/toast-store";
import { ContextMenu, ContextMenuItem, ContextMenuSeparator, ContextMenuSubMenu } from "@/components/ui/context-menu";
import { useContextMenu } from "@/hooks/use-context-menu";
import type { IJMAPClient } from '@/lib/jmap/client-interface';

/**
 * Split a per-account calendar list into "owned" (the user's own) and
 * "shared" sub-buckets, then group shared by the owning principal so each
 * delegator gets its own sub-section.
 */
type AccountCalendarSplit = {
  owned: Calendar[];
  sharedGroups: { label: string; calendars: Calendar[] }[];
};

function splitAccountCalendars(list: Calendar[]): AccountCalendarSplit {
  const owned: Calendar[] = [];
  const sharedBuckets = new Map<string, { label: string; calendars: Calendar[] }>();
  for (const cal of list) {
    if (cal.isShared) {
      const key = cal.accountId || cal.accountName || cal.id;
      const bucket = sharedBuckets.get(key);
      if (bucket) {
        bucket.calendars.push(cal);
      } else {
        sharedBuckets.set(key, { label: cal.accountName || key, calendars: [cal] });
      }
    } else {
      owned.push(cal);
    }
  }
  return { owned, sharedGroups: Array.from(sharedBuckets.values()) };
}

interface CalendarSidebarPanelProps {
  calendars: Calendar[];
  selectedCalendarIds: string[];
  onToggleVisibility: (id: string) => void;
  onColorChange?: (calendarId: string, color: string) => void;
  onResetColor?: (calendar: Calendar) => void;
  onShareCalendar?: (calendar: Calendar) => void;
  onCreateEvent?: (calendar: Calendar) => void;
  onClearCalendar?: (calendar: Calendar) => void;
  onDeleteCalendar?: (calendar: Calendar) => void;
  onCreateCalendar?: () => void;
  onSubscribe?: () => void;
  onEditSubscription?: (subscriptionId: string) => void;
  client?: IJMAPClient | null;
  /**
   * When true, render one collapsible section per connected local account,
   * mirroring the mail sidebar's Pro-shell layout. Calendars are bucketed
   * by their `localAccountId` and the active account is shown first.
   */
  multiAccountMode?: boolean;
}

export function CalendarSidebarPanel({
  calendars,
  selectedCalendarIds,
  onToggleVisibility,
  onColorChange,
  onResetColor,
  onShareCalendar,
  onCreateEvent,
  onClearCalendar,
  onDeleteCalendar,
  onCreateCalendar,
  onSubscribe,
  onEditSubscription,
  client,
  multiAccountMode,
}: CalendarSidebarPanelProps) {
  const t = useTranslations("calendar");
  const tSub = useTranslations("calendar.subscription");
  const tMgmt = useTranslations("calendar.management");
  const isSubscriptionCalendar = useCalendarStore((s) => s.isSubscriptionCalendar);
  const allSubs = useCalendarStore((s) => s.icalSubscriptions);
  const currentAccountId = client?.getAccountId();
  const icalSubscriptions = useMemo(
    () => allSubs.filter(s => !s.accountId || s.accountId === currentAccountId),
    [allSubs, currentAccountId],
  );
  const refreshICalSubscription = useCalendarStore((s) => s.refreshICalSubscription);
  const removeICalSubscription = useCalendarStore((s) => s.removeICalSubscription);
  const timeFormat = useSettingsStore((s) => s.timeFormat);
  const sharedCalendarColors = useSettingsStore((s) => s.sharedCalendarColors);
  const enableCalendarTasks = useSettingsStore((s) => s.enableCalendarTasks);
  const tasks = useTaskStore((s) => s.tasks);
  const setViewMode = useCalendarStore((s) => s.setViewMode);

  const pendingTaskCount = useMemo(() => tasks.filter(t => t.progress !== 'completed' && t.progress !== 'cancelled').length, [tasks]);
  const overdueTaskCount = useMemo(() => {
    const now = new Date();
    return tasks.filter(t => t.progress !== 'completed' && t.progress !== 'cancelled' && t.due && new Date(t.due) < now).length;
  }, [tasks]);

  const { contextMenu, openContextMenu, closeContextMenu, menuRef } = useContextMenu<Calendar>();
  const [refreshingSubId, setRefreshingSubId] = useState<string | null>(null);

  // Persisted across mounts so toggle state survives tab switches in the
  // Pro shell (same key family as the mail sidebar's account collapse).
  const [collapsedAccountGroups, setCollapsedAccountGroups] = useState<Set<string>>(() => {
    try {
      const raw = localStorage.getItem('calendar-sidebar-collapsed-accounts');
      return raw ? new Set(JSON.parse(raw)) : new Set();
    } catch { return new Set(); }
  });
  const toggleAccountGroup = (key: string) => {
    setCollapsedAccountGroups((prev) => {
      const next = new Set(prev);
      if (next.has(key)) next.delete(key); else next.add(key);
      try { localStorage.setItem('calendar-sidebar-collapsed-accounts', JSON.stringify(Array.from(next))); } catch { /* */ }
      return next;
    });
  };

  const localAccounts = useAccountStore((s) => s.accounts);
  const activeLocalAccountId = useAccountStore((s) => s.activeAccountId);

  const personalCalendars = useMemo(() => calendars.filter(c => !c.isShared), [calendars]);
  const sharedAccountGroups = useMemo(() => {
    const shared = calendars.filter(c => c.isShared);
    const groups = new Map<string, { accountName: string; calendars: Calendar[] }>();
    for (const cal of shared) {
      const key = cal.accountId || cal.accountName || cal.id;
      if (!groups.has(key)) {
        groups.set(key, { accountName: cal.accountName || key, calendars: [] });
      }
      groups.get(key)!.calendars.push(cal);
    }
    return Array.from(groups.values());
  }, [calendars]);

  /**
   * Pro / multi-account grouping: every calendar bucketed by its owning
   * local account. Active account comes first, then the rest in their
   * account-store order. Calendars without a `localAccountId` (e.g. the
   * birthday calendar) fall into a separate "other" bucket so they still
   * render.
   */
  const localAccountGroups = useMemo(() => {
    if (!multiAccountMode) return [];
    const byAccount = new Map<string, Calendar[]>();
    for (const cal of calendars) {
      const key = cal.localAccountId || '__other__';
      const list = byAccount.get(key) ?? [];
      list.push(cal);
      byAccount.set(key, list);
    }
    const ordered: { key: string; label: string; split: AccountCalendarSplit }[] = [];
    // Active account first.
    if (activeLocalAccountId && byAccount.has(activeLocalAccountId)) {
      const acct = localAccounts.find(a => a.id === activeLocalAccountId);
      ordered.push({
        key: activeLocalAccountId,
        label: acct?.label || acct?.email || acct?.username || activeLocalAccountId,
        split: splitAccountCalendars(byAccount.get(activeLocalAccountId)!),
      });
      byAccount.delete(activeLocalAccountId);
    }
    // Then the rest in account-store order so the layout matches the mail sidebar.
    for (const acct of localAccounts) {
      if (!byAccount.has(acct.id)) continue;
      ordered.push({
        key: acct.id,
        label: acct.label || acct.email || acct.username,
        split: splitAccountCalendars(byAccount.get(acct.id)!),
      });
      byAccount.delete(acct.id);
    }
    // Any leftover buckets (deleted accounts, untagged calendars).
    for (const [key, list] of byAccount.entries()) {
      const fallbackLabel = key === '__other__'
        ? t('my_calendars')
        : list[0]?.accountName || key;
      ordered.push({ key, label: fallbackLabel, split: splitAccountCalendars(list) });
    }
    return ordered;
  }, [multiAccountMode, calendars, localAccounts, activeLocalAccountId, t]);

  const getSubscriptionForCalendar = (calendarId: string) => {
    return icalSubscriptions.find(s => s.calendarId === calendarId);
  };

  const handleRefreshSubscription = async (subId: string) => {
    if (!client) return;
    setRefreshingSubId(subId);
    try {
      await refreshICalSubscription(client, subId);
      toast.success(tSub('refresh_success'));
    } catch {
      toast.error(tSub('refresh_error'));
    } finally {
      setRefreshingSubId(null);
    }
  };

  const handleUnsubscribe = async (subId: string) => {
    if (!client) return;
    try {
      await removeICalSubscription(client, subId);
      toast.success(tSub('deleted'));
    } catch {
      toast.error(tSub('delete_error'));
    }
  };

  if (calendars.length === 0 && !onSubscribe) return null;

  const renderCalendarItem = (cal: Calendar) => {
    const isVisible = selectedCalendarIds.includes(cal.id);
    const color = cal.color || "#3b82f6";
    const hasMenu = isSubscriptionCalendar(cal.id) ? !!client : true;

    return (
      <div key={cal.id} className="relative">
        <button
          onClick={() => onToggleVisibility(cal.id)}
          onContextMenu={hasMenu ? (e) => openContextMenu(e, cal) : undefined}
          className={cn(
            "flex items-center gap-2 w-full px-1.5 py-1 rounded-md text-sm transition-colors duration-150",
            "hover:bg-muted"
          )}
        >
          <span
            className={cn(
              "w-3 h-3 rounded-sm border-2 flex-shrink-0 transition-colors",
              isVisible ? "border-transparent" : "border-muted-foreground/40 bg-transparent"
            )}
            style={isVisible ? { backgroundColor: color, borderColor: color } : undefined}
          />
          <span className={cn("truncate", !isVisible && "text-muted-foreground")}>
            {cal.name}
          </span>
          {isSubscriptionCalendar(cal.id) && (
            <>
              <Globe className="w-3 h-3 text-muted-foreground flex-shrink-0" />
              {refreshingSubId === getSubscriptionForCalendar(cal.id)?.id && (
                <RefreshCw className="w-3 h-3 text-muted-foreground flex-shrink-0 animate-spin" />
              )}
            </>
          )}
          {cal.id === BIRTHDAY_CALENDAR_ID && (
            <Cake className="w-3 h-3 text-muted-foreground flex-shrink-0" />
          )}
          {!cal.isShared && Object.keys(cal.shareWith || {}).length > 0 && (
            <Users
              className="w-3 h-3 text-muted-foreground flex-shrink-0"
              aria-label={tMgmt('share')}
            />
          )}
        </button>
      </div>
    );
  };

  const renderCalendarMenu = () => {
    const cal = contextMenu.data;
    if (!cal) return null;

    if (isSubscriptionCalendar(cal.id)) {
      const sub = getSubscriptionForCalendar(cal.id);
      if (!sub || !client) return null;
      return (
        <ContextMenu ref={menuRef} isOpen={contextMenu.isOpen} position={contextMenu.position} onClose={closeContextMenu}>
          <ContextMenuItem
            icon={Pencil}
            label={tSub('edit')}
            onClick={() => { closeContextMenu(); onEditSubscription?.(sub.id); }}
          />
          <ContextMenuItem
            icon={RefreshCw}
            label={tSub('refresh')}
            onClick={() => { closeContextMenu(); handleRefreshSubscription(sub.id); }}
          />
          <ContextMenuSeparator />
          <ContextMenuItem
            icon={Trash2}
            label={tSub('unsubscribe')}
            onClick={() => { closeContextMenu(); handleUnsubscribe(sub.id); }}
            destructive
          />
          {sub.lastRefreshed && (
            <div className="px-3 py-1.5 text-xs text-muted-foreground border-t border-border mt-1 pt-1">
              {tSub('last_refreshed', { time: formatDateTime(sub.lastRefreshed, timeFormat, { month: 'short', day: 'numeric', year: 'numeric' }) })}
            </div>
          )}
        </ContextMenu>
      );
    }

    const isBirthday = cal.id === BIRTHDAY_CALENDAR_ID;
    const canCreate = onCreateEvent && !isBirthday && cal.myRights?.mayWriteOwn !== false;
    const canShare = onShareCalendar && cal.myRights?.mayShare && !cal.isShared;
    const canChangeColor = !!onColorChange;
    const hasColorOverride = !!cal.isShared && !!sharedCalendarColors[sharedCalendarColorKey(cal)];
    const canResetColor = !!onResetColor && hasColorOverride;
    const canClear = onClearCalendar && !isBirthday && cal.myRights?.mayDelete !== false;
    const canDelete = onDeleteCalendar && !isBirthday && !cal.isDefault && !cal.isShared;
    const showSeparator = (canCreate || canShare || canChangeColor || canResetColor) && (canClear || canDelete);
    const color = cal.color || "#3b82f6";

    return (
      <ContextMenu ref={menuRef} isOpen={contextMenu.isOpen} position={contextMenu.position} onClose={closeContextMenu}>
        {canCreate && (
          <ContextMenuItem
            icon={Plus}
            label={tMgmt('new_event_in_calendar')}
            onClick={() => { closeContextMenu(); onCreateEvent(cal); }}
          />
        )}
        {canShare && (
          <ContextMenuItem
            icon={Users}
            label={tMgmt('share')}
            onClick={() => { closeContextMenu(); onShareCalendar(cal); }}
          />
        )}
        {canChangeColor && (
          <ContextMenuSubMenu icon={Palette} label={tMgmt('change_color')}>
            <div className="px-2 py-1.5 w-[200px]">
              <CalendarColorPicker
                value={color}
                onChange={(c) => { onColorChange(cal.id, c); closeContextMenu(); }}
                allowCustom
              />
            </div>
          </ContextMenuSubMenu>
        )}
        {canResetColor && (
          <ContextMenuItem
            icon={Shuffle}
            label={tMgmt('random_color')}
            onClick={() => { closeContextMenu(); onResetColor!(cal); }}
          />
        )}
        {showSeparator && <ContextMenuSeparator />}
        {canClear && (
          <ContextMenuItem
            icon={Eraser}
            label={tMgmt('clear_events')}
            onClick={() => { closeContextMenu(); onClearCalendar(cal); }}
          />
        )}
        {canDelete && (
          <ContextMenuItem
            icon={Trash2}
            label={tMgmt('delete')}
            onClick={() => { closeContextMenu(); onDeleteCalendar(cal); }}
            destructive
          />
        )}
      </ContextMenu>
    );
  };

  return (
    <div className="mt-4">
      {enableCalendarTasks && (
        <button
          onClick={() => setViewMode('tasks')}
          className="flex items-center gap-2 w-full px-1.5 py-1.5 mb-3 rounded-md text-sm hover:bg-muted transition-colors"
        >
          <ListTodo className="w-4 h-4 text-muted-foreground" />
          <span>{t('tasks.label')}</span>
          {pendingTaskCount > 0 && (
            <span className="ml-auto text-xs text-muted-foreground">{pendingTaskCount}</span>
          )}
          {overdueTaskCount > 0 && (
            <span className="text-xs text-destructive font-medium">{overdueTaskCount} {t('tasks.filter_overdue').toLowerCase()}</span>
          )}
        </button>
      )}
      {multiAccountMode && localAccountGroups.length > 0 ? (
        <>
          {localAccountGroups.map((group, idx) => {
            const expanded = !collapsedAccountGroups.has(group.key);
            const isActive = group.key === activeLocalAccountId;
            const { owned, sharedGroups } = group.split;
            return (
              <div key={group.key} className={cn(idx === 0 ? "" : "mt-3")}>
                <button
                  onClick={() => toggleAccountGroup(group.key)}
                  className="group w-full flex items-center gap-1.5 px-1 py-1 rounded-sm hover:bg-muted/40 transition-colors"
                >
                  {expanded ? (
                    <ChevronDown className="w-3.5 h-3.5 text-muted-foreground flex-shrink-0" />
                  ) : (
                    <ChevronRight className="w-3.5 h-3.5 text-muted-foreground flex-shrink-0" />
                  )}
                  <User className="w-3.5 h-3.5 text-muted-foreground flex-shrink-0" />
                  <span className="text-xs font-semibold text-foreground/90 truncate">
                    {group.label}
                  </span>
                  {isActive && onCreateCalendar && (
                    <span
                      role="button"
                      tabIndex={0}
                      onClick={(e) => { e.stopPropagation(); onCreateCalendar(); }}
                      onKeyDown={(e) => {
                        if (e.key === 'Enter' || e.key === ' ') {
                          e.preventDefault();
                          e.stopPropagation();
                          onCreateCalendar();
                        }
                      }}
                      className="ml-auto p-0.5 rounded text-muted-foreground/70 opacity-0 group-hover:opacity-100 hover:text-foreground hover:bg-muted transition-colors cursor-pointer"
                      title={tMgmt('add_calendar')}
                    >
                      <Plus className="w-3 h-3" />
                    </span>
                  )}
                </button>
                {expanded && (
                  <div className="mt-1 pl-3">
                    {owned.length > 0 && (
                      <div>
                        <div className="px-1 mb-1 text-[10px] font-medium text-muted-foreground/80 uppercase tracking-wider">
                          {t('my_calendars')}
                        </div>
                        <div className="space-y-0.5">
                          {owned.map(renderCalendarItem)}
                        </div>
                      </div>
                    )}
                    {sharedGroups.map((sg) => (
                      <div key={`${group.key}-shared-${sg.label}`} className="mt-2">
                        <div className="px-1 mb-1 text-[10px] font-medium text-muted-foreground/80 uppercase tracking-wider flex items-center gap-1">
                          <Share2 className="w-3 h-3" />
                          {sg.label}
                        </div>
                        <div className="space-y-0.5">
                          {sg.calendars.map(renderCalendarItem)}
                        </div>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            );
          })}
        </>
      ) : (
        <>
          <div className="flex items-center justify-between mb-2 px-1 group">
            {onCreateCalendar ? (
              <button
                onClick={onCreateCalendar}
                className="text-xs font-medium text-muted-foreground uppercase tracking-wider hover:text-foreground transition-colors flex items-center gap-1.5"
                title={tMgmt('add_calendar')}
              >
                {t('my_calendars')}
                <Plus className="w-3 h-3 opacity-0 group-hover:opacity-100 transition-opacity" />
              </button>
            ) : (
              <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
                {t('my_calendars')}
              </h3>
            )}
          </div>
          <div className="space-y-0.5">
            {personalCalendars.map(renderCalendarItem)}
          </div>

          {sharedAccountGroups.map((group) => (
            <div key={group.accountName} className="mt-4">
              <h3 className="text-xs font-medium text-muted-foreground uppercase tracking-wider mb-2 px-1 flex items-center gap-1.5">
                <Share2 className="w-3 h-3" />
                {group.accountName}
              </h3>
              <div className="space-y-0.5">
                {group.calendars.map(renderCalendarItem)}
              </div>
            </div>
          ))}
        </>
      )}

      {renderCalendarMenu()}
    </div>
  );
}
