import { type ReactElement, useState } from "react";
import {
  Building2,
  Calendar,
  ChevronDown,
  ChevronRight,
  ChevronUp,
  Equal,
  type LucideIcon,
  Mail,
  Phone,
  User,
} from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { cn } from "@/lib/utils";
import { formatDateShort } from "@/lib/format-date";

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export type Priority = "HIGH" | "MEDIUM" | "LOW" | "NONE";

export type ActivityType =
  | "created"
  | "moved"
  | "edited"
  | "comment-added"
  | "label-added"
  | "label-removed"
  | "marked-done";

export interface Subtask {
  id: string;
  title: string;
  completed: boolean;
}

export interface TaskAttachment {
  id: string;
  name: string;
  /** File size in bytes. */
  size: number;
  /** MIME type, e.g. "image/png". */
  type: string;
  /** Object URL or data URL for local preview. */
  url: string;
}

export interface ClientContact {
  id?: string;
  name: string;
  email?: string;
  phone?: string;
  company?: string;
}

export interface KanbanLabel {
  id: string;
  name: string;
  /** Any valid CSS color (hex, rgb, hsl). */
  color: string;
}

export interface KanbanComment {
  id: string;
  /** Maps to a staff member id in the consuming app. */
  authorId: string;
  body: string;
  createdAt: string;
}

export interface ActivityEntry {
  id: string;
  type: ActivityType;
  /** Maps to a staff member id in the consuming app. */
  actorId: string;
  at: string;
  payload?: Record<string, string>;
}

export interface KanbanTask {
  id: string;
  title: string;
  description?: string;
  assigneeName?: string;
  /** Prefer this over `assigneeName` when available — maps to a staff id. */
  assigneeId?: string;
  /** Support staff assisting the assignee (advisor). */
  supporterName?: string;
  /** ISO date string. */
  startDate?: string;
  /** ISO date string. */
  dueDate?: string;
  priority: Priority;
  /** How many days this task has been sitting in the current column. */
  daysInColumn?: number;
  subtasks: Subtask[];
  /** Long-form notes shown in the detail drawer's Notes tab. */
  notes?: string;
  /** Label ids resolved by the consuming app via the `labels` card prop. */
  labelIds?: string[];
  /** Comments shown in the detail drawer's Comments tab. */
  comments?: KanbanComment[];
  /** Audit log shown in the detail drawer's Activity tab. */
  activity?: ActivityEntry[];
  /** Files and images attached to this task. */
  attachments?: TaskAttachment[];
  /** End-customer or lead this task is about. Rendered as a contact strip. */
  clientContact?: ClientContact;
  /**
   * Staff ids watching this card (Jira-style). Watchers receive card-activity
   * emails. Populated automatically for the creator and assignee; anyone can
   * add or remove themselves via the detail drawer's Watch control.
   */
  watcherIds?: string[];
  /** Staff id of whoever created the card. Auto-added to `watcherIds`. */
  createdById?: string;
}

export interface KanbanCardProps {
  task: KanbanTask;
  /**
   * Marks the card as complete (e.g. it sits in a "Done"/completion column).
   * Suppresses due-date urgency states — a done task is never "Overdue"/"Due
   * today"; its due date renders as a plain, muted date instead.
   */
  isComplete?: boolean;
  /** When true, the subtasks section is shown. */
  showSubtasks?: boolean;
  /**
   * Resolved label objects for display. Pass the labels that match
   * `task.labelIds`. The component is pure — it does not resolve ids itself.
   */
  labels?: KanbanLabel[];
  onSubtaskToggle?: (taskId: string, subtaskId: string) => void;
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

// Priority uses Jira-style directional icons (not a color dot) so the meaning
// reads as an actual priority rather than a status chip: High = up chevron,
// Medium = equals, Low = down chevron. NONE renders nothing.
const PRIORITY_CONFIG: Record<
  Priority,
  { label: string; color: string; icon: LucideIcon | null }
> = {
  HIGH: { label: "High", color: "var(--color-destructive)", icon: ChevronUp },
  MEDIUM: { label: "Medium", color: "var(--color-warning)", icon: Equal },
  LOW: { label: "Low", color: "var(--color-success)", icon: ChevronDown },
  NONE: { label: "None", color: "transparent", icon: null },
};

// ---------------------------------------------------------------------------
// PriorityIcon — shared Jira-style priority glyph, reused by the card and the
// task-form PrioritySelect so both surfaces stay visually consistent.
// ---------------------------------------------------------------------------

export interface PriorityIconProps {
  priority: Priority;
  className?: string;
}

export function PriorityIcon({
  priority,
  className,
}: PriorityIconProps): ReactElement | null {
  const { label, color, icon: Icon } = PRIORITY_CONFIG[priority];
  if (!Icon) return null;
  return (
    <Icon
      className={cn("size-4 shrink-0", className)}
      style={{ color }}
      strokeWidth={3}
      aria-label={`${label} priority`}
    />
  );
}

type DueDateState = "overdue" | "today" | "soon" | "ok";

const getDueDateState = (iso: string): DueDateState => {
  const due = new Date(iso);
  const now = new Date();
  const dueDay = new Date(due.getFullYear(), due.getMonth(), due.getDate());
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const diff = Math.round(
    (dueDay.getTime() - today.getTime()) / (1000 * 60 * 60 * 24),
  );
  if (diff < 0) return "overdue";
  if (diff === 0) return "today";
  if (diff <= 2) return "soon";
  return "ok";
};

// ---------------------------------------------------------------------------
// Sub-components
// ---------------------------------------------------------------------------

function LabelChips({ labels }: { labels: KanbanLabel[] }): ReactElement {
  return (
    <div className="flex flex-wrap gap-1">
      {labels.slice(0, 4).map((label) => (
        <Badge
          key={label.id}
          className="px-1.5 py-0.5"
          style={{
            backgroundColor: `${label.color}22`,
            color: label.color,
            borderColor: `${label.color}55`,
          }}
        >
          {label.name}
        </Badge>
      ))}
      {labels.length > 4 && (
        <Badge variant="secondary" className="px-1.5 py-0.5">
          +{labels.length - 4}
        </Badge>
      )}
    </div>
  );
}

function ContactStrip({ contact }: { contact: ClientContact }): ReactElement {
  return (
    <div className="flex flex-col gap-1">
      <span className="flex items-center gap-1.5 text-caption font-semibold text-foreground">
        <User className="size-3 shrink-0" aria-hidden="true" />
        <span className="truncate">{contact.name}</span>
      </span>
      {contact.company && (
        <span className="flex items-center gap-1.5 text-caption text-muted-foreground">
          <Building2 className="size-3 shrink-0" aria-hidden="true" />
          <span className="truncate">{contact.company}</span>
        </span>
      )}
      {contact.phone && (
        <span className="flex items-center gap-1.5 text-caption text-muted-foreground">
          <Phone className="size-3 shrink-0" aria-hidden="true" />
          <span className="truncate">{contact.phone}</span>
        </span>
      )}
      {contact.email && (
        <span className="flex items-center gap-1.5 text-caption text-muted-foreground">
          <Mail className="size-3 shrink-0" aria-hidden="true" />
          <span className="truncate">{contact.email}</span>
        </span>
      )}
    </div>
  );
}

function DatesRow({
  startDate,
  dueDate,
  isComplete = false,
}: {
  startDate?: string;
  dueDate?: string;
  isComplete?: boolean;
}): ReactElement | null {
  if (!startDate && !dueDate) return null;
  // A complete task is never overdue/due-today — show its due date as a plain
  // muted date instead of an urgency state.
  const state = dueDate ? (isComplete ? "ok" : getDueDateState(dueDate)) : null;
  return (
    <div className="flex items-center gap-1 text-caption tabular-nums">
      <Calendar className="size-3 shrink-0 text-muted-foreground" aria-hidden />
      {startDate && (
        <span className="text-muted-foreground">
          {formatDateShort(startDate)}
        </span>
      )}
      {startDate && dueDate && <span className="text-muted-foreground">→</span>}
      {dueDate && state && (
        <span
          className={cn(
            state === "overdue" && "font-medium text-destructive",
            state === "today" && "font-medium text-warning",
            state === "soon" && "text-warning",
            state === "ok" && "text-muted-foreground",
          )}
        >
          {state === "overdue"
            ? `Overdue · ${formatDateShort(dueDate)}`
            : state === "today"
              ? "Due today"
              : formatDateShort(dueDate)}
        </span>
      )}
    </div>
  );
}

function PersonRow({
  label,
  name,
}: {
  label: string;
  name: string;
}): ReactElement {
  return (
    <div className="flex min-w-0 items-center gap-1.5">
      <span className="shrink-0 text-caption text-muted-foreground">
        {label}:
      </span>
      <span className="truncate text-caption text-foreground">{name}</span>
    </div>
  );
}

function SubtaskProgress({ subtasks }: { subtasks: Subtask[] }): ReactElement {
  const total = subtasks.length;
  const done = subtasks.filter((s) => s.completed).length;
  return (
    <div className="flex items-center gap-2">
      <div
        className="flex flex-1 gap-0.5"
        role="progressbar"
        aria-valuenow={done}
        aria-valuemax={total}
        aria-label={`${done} of ${total} subtasks complete`}
      >
        {subtasks.map((s, i) => (
          <div
            key={s.id}
            className={cn("h-1.5 flex-1", i < done ? "bg-primary" : "bg-muted")}
          />
        ))}
      </div>
      <span className="shrink-0 text-[10px] tabular-nums text-muted-foreground">
        {done}/{total}
      </span>
    </div>
  );
}

function SubtaskList({
  subtasks,
  taskId,
  onToggle,
}: {
  subtasks: Subtask[];
  taskId: string;
  onToggle?: (taskId: string, subtaskId: string) => void;
}): ReactElement {
  const [expanded, setExpanded] = useState(false);
  return (
    <div
      className="space-y-1 border-t border-border pt-2"
      onClick={(e) => e.stopPropagation()}
      onDoubleClick={(e) => e.stopPropagation()}
      role="presentation"
    >
      <button
        type="button"
        onClick={() => setExpanded((v) => !v)}
        className="flex w-full items-center gap-1 text-caption text-muted-foreground hover:text-foreground"
      >
        {expanded ? (
          <ChevronDown className="size-3" />
        ) : (
          <ChevronRight className="size-3" />
        )}
        Subtasks
      </button>
      {expanded && (
        <ul className="space-y-1.5 pt-1">
          {subtasks.map((s) => (
            <li key={s.id} className="flex items-center gap-2">
              <Checkbox
                checked={s.completed}
                onCheckedChange={() => onToggle?.(taskId, s.id)}
                aria-label={s.title}
              />
              <span
                className={cn(
                  "text-caption",
                  s.completed && "text-muted-foreground line-through",
                )}
              >
                {s.title}
              </span>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

export function KanbanCard({
  task,
  isComplete = false,
  showSubtasks = false,
  labels = [],
  onSubtaskToggle,
}: KanbanCardProps): ReactElement {
  const totalSubtasks = task.subtasks.length;
  const hasSubtasks = showSubtasks && totalSubtasks > 0;
  const nextSubtask = task.subtasks.find((s) => !s.completed);

  const hasFooter =
    !!task.assigneeName ||
    !!task.supporterName ||
    !!task.startDate ||
    !!task.dueDate ||
    totalSubtasks > 0 ||
    hasSubtasks;

  return (
    <Card className="border border-border bg-background py-0 gap-0">
      <CardContent className="space-y-2 p-3">
        {labels.length > 0 && <LabelChips labels={labels} />}

        <div className="flex items-start justify-between gap-2">
          <h4 className="min-w-0 flex-1 text-label-small leading-snug">
            {task.title}
          </h4>
          <PriorityIcon priority={task.priority} className="mt-0.5" />
        </div>

        {task.description && (
          <p className="line-clamp-2 text-body-small text-muted-foreground">
            {task.description}
          </p>
        )}

        {task.clientContact && <ContactStrip contact={task.clientContact} />}

        {hasFooter && <hr className="border-border" />}

        {task.assigneeName && (
          <PersonRow label="Assignee" name={task.assigneeName} />
        )}

        {task.supporterName && (
          <PersonRow label="Supporter" name={task.supporterName} />
        )}

        <DatesRow
          startDate={task.startDate}
          dueDate={task.dueDate}
          isComplete={isComplete}
        />

        {totalSubtasks > 0 && <SubtaskProgress subtasks={task.subtasks} />}

        {hasSubtasks && nextSubtask && (
          <div className="space-y-0.5 border border-primary/30 bg-primary/5 px-2.5 py-1.5">
            <p className="text-caption text-muted-foreground">
              Next to complete:
            </p>
            <p className="text-label-small leading-snug">{nextSubtask.title}</p>
          </div>
        )}

        {hasSubtasks && (
          <SubtaskList
            subtasks={task.subtasks}
            taskId={task.id}
            onToggle={onSubtaskToggle}
          />
        )}
      </CardContent>
    </Card>
  );
}

export default KanbanCard;
