import { useCallback, useEffect, useMemo, useState } from 'react';

import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer';
import { CollapsibleTeamSection } from '@renderer/components/team/CollapsibleTeamSection';
import { MemberBadge } from '@renderer/components/team/MemberBadge';
import { MemberLogsTab } from '@renderer/components/team/members/MemberLogsTab';
import { Badge } from '@renderer/components/ui/badge';
import { Button } from '@renderer/components/ui/button';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@renderer/components/ui/dialog';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@renderer/components/ui/select';
import { getTeamColorSet } from '@renderer/constants/teamColors';
import { markAsRead } from '@renderer/services/commentReadStorage';
import { useStore } from '@renderer/store';
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
import {
  buildMemberColorMap,
  KANBAN_COLUMN_DISPLAY,
  TASK_STATUS_LABELS,
  TASK_STATUS_STYLES,
} from '@renderer/utils/memberHelpers';
import { formatDistanceToNow } from 'date-fns';
import {
  AlignLeft,
  ArrowLeftFromLine,
  ArrowRightFromLine,
  Clock,
  FileCode,
  FileDiff,
  HelpCircle,
  Link2,
  Loader2,
  MessageSquare,
  PenLine,
  ScrollText,
  Trash2,
} from 'lucide-react';

import { TaskCommentInput } from './TaskCommentInput';
import { TaskCommentsSection } from './TaskCommentsSection';

import type { KanbanTaskState, ResolvedTeamMember, TeamTaskWithKanban } from '@shared/types';

interface TaskDetailDialogProps {
  open: boolean;
  task: TeamTaskWithKanban | null;
  teamName: string;
  kanbanTaskState?: KanbanTaskState;
  taskMap: Map<string, TeamTaskWithKanban>;
  members: ResolvedTeamMember[];
  onClose: () => void;
  onScrollToTask?: (taskId: string) => void;
  onOwnerChange?: (taskId: string, owner: string | null) => void;
  onViewChanges?: (taskId: string, filePath?: string) => void;
  onDeleteTask?: (taskId: string) => void;
  /** Extra content rendered in the dialog header (e.g. "Open team" button). */
  headerExtra?: React.ReactNode;
}

export const TaskDetailDialog = ({
  open,
  task,
  teamName,
  kanbanTaskState,
  taskMap,
  members,
  onClose,
  onScrollToTask,
  onOwnerChange,
  onViewChanges,
  onDeleteTask,
  headerExtra,
}: TaskDetailDialogProps): React.JSX.Element => {
  const colorMap = useMemo(() => buildMemberColorMap(members), [members]);
  const currentTask = task ? (taskMap.get(task.id) ?? task) : null;
  const [replyTo, setReplyTo] = useState<{
    taskId: string;
    author: string;
    text: string;
  } | null>(null);
  const handleReply = useCallback(
    (author: string, text: string) => {
      if (currentTask) setReplyTo({ taskId: currentTask.id, author, text });
    },
    [currentTask]
  );
  const clearReply = useCallback(() => setReplyTo(null), []);

  const handleClose = useCallback(() => {
    setReplyTo(null);
    onClose();
  }, [onClose]);

  const effectiveReplyTo =
    replyTo && replyTo.taskId === currentTask?.id
      ? { author: replyTo.author, text: replyTo.text }
      : null;

  useEffect(() => {
    if (!open || !currentTask) return;
    const comments = currentTask.comments ?? [];
    if (comments.length === 0) return;
    const latest = Math.max(...comments.map((c) => new Date(c.createdAt).getTime()));
    if (latest > 0) markAsRead(teamName, currentTask.id, latest);
  }, [open, teamName, currentTask]);

  // Lazy-load task changes when dialog is open and task is completed
  const isTaskCompleted = currentTask?.status === 'completed';
  const setTaskNeedsClarification = useStore((s) => s.setTaskNeedsClarification);
  const activeChangeSet = useStore((s) => s.activeChangeSet);
  const changeSetLoading = useStore((s) => s.changeSetLoading);
  const fetchTaskChanges = useStore((s) => s.fetchTaskChanges);

  // Use the lightweight cache to know if changes exist before full data loads
  const changesCacheKey = currentTask ? `${teamName}:${currentTask.id}` : '';
  const taskKnownHasChanges = useStore((s) => s.taskHasChanges[changesCacheKey]) === true;

  const taskChangesFiles = useMemo(() => {
    if (!activeChangeSet || !currentTask) return null;
    if ('taskId' in activeChangeSet && activeChangeSet.taskId === currentTask.id) {
      return activeChangeSet.files;
    }
    return null;
  }, [activeChangeSet, currentTask]);

  useEffect(() => {
    if (!open || !currentTask || !isTaskCompleted || !onViewChanges) return;
    // Only fetch if we don't already have data for this task
    if (taskChangesFiles !== null) return;
    void fetchTaskChanges(teamName, currentTask.id);
  }, [
    open,
    currentTask,
    isTaskCompleted,
    teamName,
    fetchTaskChanges,
    taskChangesFiles,
    onViewChanges,
  ]);

  const handleDependencyClick = (taskId: string): void => {
    handleClose();
    onScrollToTask?.(taskId);
  };

  if (!currentTask) {
    return (
      <Dialog open={open} onOpenChange={(v) => !v && handleClose()}>
        <DialogContent className="sm:max-w-4xl">
          <DialogHeader>
            <DialogTitle>Task not found</DialogTitle>
          </DialogHeader>
        </DialogContent>
      </Dialog>
    );
  }

  const kanbanColumn = kanbanTaskState?.column ?? currentTask.kanbanColumn;
  const status = currentTask.status;
  const statusStyle =
    kanbanColumn && KANBAN_COLUMN_DISPLAY[kanbanColumn]
      ? {
          bg: KANBAN_COLUMN_DISPLAY[kanbanColumn].bg,
          text: KANBAN_COLUMN_DISPLAY[kanbanColumn].text,
        }
      : TASK_STATUS_STYLES[status];
  const statusLabel =
    kanbanColumn && KANBAN_COLUMN_DISPLAY[kanbanColumn]
      ? KANBAN_COLUMN_DISPLAY[kanbanColumn].label
      : TASK_STATUS_LABELS[status];
  const blockedByIds = currentTask.blockedBy?.filter((id) => id.length > 0) ?? [];
  const blocksIds = currentTask.blocks?.filter((id) => id.length > 0) ?? [];
  const relatedIds = (currentTask.related ?? []).filter(
    (id) => id.length > 0 && id !== currentTask.id
  );
  const relatedByIds = Array.from(taskMap.values())
    .filter(
      (t) =>
        t.id !== currentTask.id && Array.isArray(t.related) && t.related.includes(currentTask.id)
    )
    .map((t) => t.id);
  const isTodo = status === 'pending' && !kanbanColumn;
  const canReassign = isTodo && onOwnerChange;

  return (
    <Dialog open={open} onOpenChange={(v) => !v && onClose()}>
      <DialogContent className="min-w-0 sm:max-w-4xl">
        <DialogHeader>
          <div className="flex items-center gap-2">
            <Badge variant="secondary" className="px-1.5 py-0 text-[10px] font-normal">
              #{currentTask.id}
            </Badge>
            <span
              className={`inline-flex rounded-full px-2 py-0.5 text-[10px] font-medium ${statusStyle.bg} ${statusStyle.text}`}
            >
              {statusLabel}
            </span>
            {headerExtra ? <div className="ml-auto mr-4">{headerExtra}</div> : null}
          </div>
          <DialogTitle className="text-base">{currentTask.subject}</DialogTitle>
          {currentTask.activeForm ? (
            <DialogDescription>{currentTask.activeForm}</DialogDescription>
          ) : null}
        </DialogHeader>

        {/* Metadata */}
        <div className="grid grid-cols-2 gap-x-4 gap-y-2 text-xs sm:grid-cols-3">
          <div className="flex min-w-0 items-center gap-2">
            {canReassign ? (
              <Select
                value={currentTask.owner ?? '__unassigned__'}
                onValueChange={(v) => {
                  onOwnerChange(currentTask.id, v === '__unassigned__' ? null : v);
                }}
              >
                <SelectTrigger className="h-8 w-auto min-w-[140px] text-xs">
                  <SelectValue placeholder="Unassigned" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="__unassigned__">Unassigned</SelectItem>
                  {members.map((m) => {
                    const role = formatAgentRole(m.role) ?? formatAgentRole(m.agentType);
                    const resolvedColor = colorMap.get(m.name);
                    const memberColor = resolvedColor ? getTeamColorSet(resolvedColor) : null;
                    return (
                      <SelectItem key={m.name} value={m.name}>
                        <span className="inline-flex items-center gap-1.5">
                          {memberColor ? (
                            <span
                              className="inline-block size-2 shrink-0 rounded-full"
                              style={{ backgroundColor: memberColor.border }}
                            />
                          ) : null}
                          <span style={memberColor ? { color: memberColor.text } : undefined}>
                            {m.name}
                          </span>
                          {role ? (
                            <span className="text-[var(--color-text-muted)]">({role})</span>
                          ) : null}
                        </span>
                      </SelectItem>
                    );
                  })}
                </SelectContent>
              </Select>
            ) : currentTask.owner ? (
              <MemberBadge
                name={currentTask.owner}
                color={colorMap.get(currentTask.owner)}
                size="md"
              />
            ) : (
              <span className="text-xs text-[var(--color-text-muted)]">&mdash;</span>
            )}
          </div>
          {currentTask.createdBy ? (
            <div className="flex items-center gap-1.5 text-[var(--color-text-muted)]">
              <PenLine size={12} />
              <span className="text-[var(--color-text-secondary)]">{currentTask.createdBy}</span>
            </div>
          ) : null}
          {currentTask.createdAt
            ? (() => {
                const date = new Date(currentTask.createdAt);
                return isNaN(date.getTime()) ? null : (
                  <div className="flex items-center gap-1.5 text-[var(--color-text-muted)]">
                    <Clock size={12} />
                    <span className="text-[var(--color-text-secondary)]">
                      {formatDistanceToNow(date, { addSuffix: true })}
                    </span>
                  </div>
                );
              })()
            : null}
        </div>

        {/* Clarification banner */}
        {currentTask.needsClarification ? (
          <div
            className={`flex items-center justify-between rounded-md px-3 py-2 text-xs ${
              currentTask.needsClarification === 'user'
                ? 'border border-red-500/20 bg-red-500/10 text-red-400'
                : 'border border-blue-500/20 bg-blue-500/10 text-blue-400'
            }`}
          >
            <span className="flex items-center gap-1.5">
              <HelpCircle size={14} />
              {currentTask.needsClarification === 'user'
                ? 'Awaiting clarification from you'
                : 'Awaiting clarification from team lead'}
            </span>
            <Button
              variant="ghost"
              size="sm"
              className="h-6 text-xs"
              onClick={(e) => {
                e.stopPropagation();
                void setTaskNeedsClarification(teamName, currentTask.id, null);
              }}
            >
              Mark resolved
            </Button>
          </div>
        ) : null}

        {/* Description */}
        <CollapsibleTeamSection title="Description" icon={<AlignLeft size={14} />} defaultOpen>
          {currentTask.description ? (
            <div className="max-h-[200px] overflow-y-auto">
              <MarkdownViewer content={currentTask.description} maxHeight="max-h-[180px]" />
            </div>
          ) : (
            <p className="text-xs text-[var(--color-text-muted)]">No description</p>
          )}
        </CollapsibleTeamSection>

        {/* Changes */}
        {isTaskCompleted && onViewChanges ? (
          <CollapsibleTeamSection
            title="Changes"
            icon={<FileDiff size={14} />}
            badge={taskChangesFiles ? taskChangesFiles.length : undefined}
            defaultOpen={taskKnownHasChanges}
          >
            {changeSetLoading || (!taskChangesFiles && taskKnownHasChanges) ? (
              <div className="flex items-center gap-2 py-2 text-xs text-[var(--color-text-muted)]">
                <Loader2 size={14} className="animate-spin" />
                Loading changes...
              </div>
            ) : taskChangesFiles && taskChangesFiles.length > 0 ? (
              <div className="max-h-[200px] space-y-0.5 overflow-y-auto">
                {taskChangesFiles.map((file) => (
                  <button
                    key={file.filePath}
                    type="button"
                    className="flex w-full items-center gap-2 rounded px-2 py-1.5 text-left text-xs transition-colors hover:bg-[var(--color-surface-raised)]"
                    onClick={() => {
                      handleClose();
                      onViewChanges(currentTask.id, file.filePath);
                    }}
                  >
                    <FileCode size={14} className="shrink-0 text-[var(--color-text-muted)]" />
                    <span className="truncate font-mono text-[var(--color-text-secondary)]">
                      {file.relativePath}
                    </span>
                    <span className="flex shrink-0 items-center gap-1.5">
                      {file.linesAdded > 0 ? (
                        <span className="text-emerald-400">+{file.linesAdded}</span>
                      ) : null}
                      {file.linesRemoved > 0 ? (
                        <span className="text-red-400">-{file.linesRemoved}</span>
                      ) : null}
                    </span>
                  </button>
                ))}
              </div>
            ) : (
              <p className="text-xs text-[var(--color-text-muted)]">No file changes detected</p>
            )}
          </CollapsibleTeamSection>
        ) : null}

        {/* Execution Logs — sessions that reference this task */}
        <CollapsibleTeamSection title="Execution Logs" icon={<ScrollText size={14} />} defaultOpen>
          <div className="min-w-0 overflow-hidden">
            <MemberLogsTab
              teamName={teamName}
              taskId={currentTask.id}
              taskOwner={currentTask.owner}
              taskStatus={currentTask.status}
            />
          </div>
        </CollapsibleTeamSection>

        <div className="mb-3 space-y-2">
          {/* Dependencies */}
          {blockedByIds.length > 0 ? (
            <div className="flex flex-wrap items-center gap-1.5">
              <span className="inline-flex items-center gap-0.5 text-xs text-yellow-300">
                <ArrowLeftFromLine size={12} />
                Blocked by
              </span>
              {blockedByIds.map((id) => {
                const depTask = taskMap.get(id);
                const isCompleted = depTask?.status === 'completed';
                return (
                  <button
                    key={id}
                    type="button"
                    className={`inline-flex items-center rounded px-1.5 py-0.5 text-[10px] font-medium transition-colors ${
                      isCompleted
                        ? 'bg-emerald-500/15 text-emerald-400 hover:bg-emerald-500/25'
                        : 'bg-yellow-500/15 text-yellow-300 hover:bg-yellow-500/25'
                    } cursor-pointer`}
                    title={depTask ? `#${id}: ${depTask.subject}` : `#${id}`}
                    onClick={() => handleDependencyClick(id)}
                  >
                    #{id}
                  </button>
                );
              })}
            </div>
          ) : null}

          {blocksIds.length > 0 ? (
            <div className="flex flex-wrap items-center gap-1.5">
              <span className="inline-flex items-center gap-0.5 text-xs text-blue-400">
                <ArrowRightFromLine size={12} />
                Blocks
              </span>
              {blocksIds.map((id) => {
                const depTask = taskMap.get(id);
                const isCompleted = depTask?.status === 'completed';
                return (
                  <button
                    key={id}
                    type="button"
                    className={`inline-flex items-center rounded px-1.5 py-0.5 text-[10px] font-medium transition-colors ${
                      isCompleted
                        ? 'bg-emerald-500/15 text-emerald-400 hover:bg-emerald-500/25'
                        : 'bg-blue-500/15 text-blue-400 hover:bg-blue-500/25'
                    } cursor-pointer`}
                    title={depTask ? `#${id}: ${depTask.subject}` : `#${id}`}
                    onClick={() => handleDependencyClick(id)}
                  >
                    #{id}
                  </button>
                );
              })}
            </div>
          ) : null}

          {/* Related tasks (explicit) */}
          {relatedIds.length > 0 || relatedByIds.length > 0 ? (
            <div className="space-y-2">
              <div className="flex items-center gap-1.5 text-xs font-medium text-[var(--color-text-muted)]">
                <Link2 size={12} />
                Related tasks
              </div>

              {relatedIds.length > 0 ? (
                <div className="flex flex-wrap items-center gap-1.5">
                  <span className="text-xs text-[var(--color-text-muted)]">Links</span>
                  {relatedIds.map((id) => {
                    const depTask = taskMap.get(id);
                    return (
                      <button
                        key={`related:${currentTask.id}:${id}`}
                        type="button"
                        className="inline-flex items-center rounded bg-purple-500/15 px-1.5 py-0.5 text-[10px] font-medium text-purple-300 transition-colors hover:bg-purple-500/25"
                        title={depTask ? `#${id}: ${depTask.subject}` : `#${id}`}
                        onClick={() => handleDependencyClick(id)}
                      >
                        #{id}
                      </button>
                    );
                  })}
                </div>
              ) : null}

              {relatedByIds.length > 0 ? (
                <div className="flex flex-wrap items-center gap-1.5">
                  <span className="text-xs text-[var(--color-text-muted)]">Linked from</span>
                  {relatedByIds.map((id) => {
                    const depTask = taskMap.get(id);
                    return (
                      <button
                        key={`related-by:${currentTask.id}:${id}`}
                        type="button"
                        className="inline-flex items-center rounded bg-fuchsia-500/15 px-1.5 py-0.5 text-[10px] font-medium text-fuchsia-300 transition-colors hover:bg-fuchsia-500/25"
                        title={depTask ? `#${id}: ${depTask.subject}` : `#${id}`}
                        onClick={() => handleDependencyClick(id)}
                      >
                        #{id}
                      </button>
                    );
                  })}
                </div>
              ) : null}
            </div>
          ) : null}

          {/* Review info */}
          {kanbanTaskState ? (
            <div className="flex items-center gap-2">
              {kanbanTaskState.reviewer ? (
                <span className="text-xs text-[var(--color-text-secondary)]">
                  Reviewer: {kanbanTaskState.reviewer}
                </span>
              ) : null}
              {kanbanTaskState.errorDescription ? (
                <span className="text-xs text-red-400">{kanbanTaskState.errorDescription}</span>
              ) : null}
            </div>
          ) : null}
        </div>

        {/* Comments */}
        <CollapsibleTeamSection
          title="Comments"
          icon={<MessageSquare size={14} />}
          badge={
            (currentTask.comments?.length ?? 0) > 0
              ? (currentTask.comments?.length ?? 0)
              : undefined
          }
          defaultOpen
        >
          <TaskCommentInput
            teamName={teamName}
            taskId={currentTask.id}
            members={members}
            replyTo={effectiveReplyTo}
            onClearReply={clearReply}
          />
          <TaskCommentsSection
            teamName={teamName}
            taskId={currentTask.id}
            comments={currentTask.comments ?? []}
            members={members}
            hideHeader
            hideInput
            onReply={handleReply}
          />
        </CollapsibleTeamSection>

        <DialogFooter className="flex items-center justify-between sm:justify-between">
          {onDeleteTask && currentTask ? (
            <Button
              variant="destructive"
              size="sm"
              onClick={() => {
                onDeleteTask(currentTask.id);
                handleClose();
              }}
            >
              <Trash2 size={14} className="mr-1" />
              Delete
            </Button>
          ) : (
            <div />
          )}
          <Button variant="outline" onClick={handleClose}>
            Close
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
};
