import { useMemo, useState } from "react";
import {
  MessageSquare,
  FileCode,
  FolderOpen,
  Plus,
  Minus,
  Circle,
  CheckCircle2,
  GitCommitHorizontal,
  Layers,
} from "lucide-react";
import type { FileDiff, ReviewComment, CommitInfo } from "./types";

type SidebarView = "files" | "commits";

interface ReviewSidebarProps {
  files: FileDiff[];
  comments: ReviewComment[];
  onFileClick: (filePath: string) => void;
  onCommentClick?: (commentId: string) => void;
  selectedCommit: string | null;
  activeFiles: FileDiff[];
  commits: CommitInfo[];
  onSelectCommit: (hash: string | null) => void;
  viewedFiles?: Set<string>;
}

export function ReviewSidebar({
  files,
  comments,
  onFileClick,
  onCommentClick,
  selectedCommit,
  activeFiles,
  commits,
  onSelectCommit,
  viewedFiles = new Set(),
}: ReviewSidebarProps) {
  const [view, setView] = useState<SidebarView>("files");

  return (
    <div className="flex h-full">
      {/* Icon strip — left edge */}
      <div className="flex flex-col items-center w-9 shrink-0 border-r border-border/50 py-1.5 gap-0.5">
        <IconTab
          icon={FileCode}
          label="Files"
          active={view === "files"}
          onClick={() => setView("files")}
        />
        <IconTab
          icon={GitCommitHorizontal}
          label="Commits"
          active={view === "commits"}
          onClick={() => setView("commits")}
          badge={commits.length > 1 ? commits.length : undefined}
        />
      </div>

      {/* Content panel */}
      <div className="flex-1 min-w-0 overflow-y-auto p-4">
        {view === "files" ? (
          <FilesView
            files={files}
            comments={comments}
            onFileClick={onFileClick}
            onCommentClick={onCommentClick}
            selectedCommit={selectedCommit}
            activeFiles={activeFiles}
            viewedFiles={viewedFiles}
          />
        ) : (
          <CommitsView
            commits={commits}
            selectedCommit={selectedCommit}
            onSelectCommit={onSelectCommit}
          />
        )}
      </div>
    </div>
  );
}

/* ─── Icon Tab ─────────────────────────────────────────── */

function IconTab({
  icon: Icon,
  label,
  active,
  onClick,
  badge,
}: {
  icon: typeof FileCode;
  label: string;
  active: boolean;
  onClick: () => void;
  badge?: number;
}) {
  return (
    <button
      onClick={onClick}
      title={label}
      className={`
        relative flex items-center justify-center w-8 h-8
        transition-all duration-150
        ${active
          ? "text-primary bg-primary/10 shadow-[inset_-2px_0_0_0] shadow-primary"
          : "text-muted-foreground hover:text-foreground hover:bg-accent/50"
        }
      `}
    >
      <Icon className="h-[15px] w-[15px]" />
      {badge !== undefined && (
        <span className="absolute -top-0.5 -right-0.5 min-w-[14px] h-[14px] rounded-full bg-primary text-primary-foreground text-[9px] font-semibold flex items-center justify-center px-0.5 leading-none">
          {badge}
        </span>
      )}
    </button>
  );
}

/* ─── Files View ───────────────────────────────────────── */

interface DirectoryGroup {
  directory: string;
  files: FileDiff[];
}

function groupFilesByDirectory(files: FileDiff[]): DirectoryGroup[] {
  const groups = new Map<string, FileDiff[]>();

  for (const file of files) {
    const lastSlash = file.newPath.lastIndexOf("/");
    const directory = lastSlash >= 0 ? file.newPath.slice(0, lastSlash + 1) : "";
    const existing = groups.get(directory);
    if (existing) {
      existing.push(file);
    } else {
      groups.set(directory, [file]);
    }
  }

  // Sort directories alphabetically, root-level files ("") last
  const sorted = Array.from(groups.entries())
    .sort(([a], [b]) => {
      if (a === "" && b !== "") return 1;
      if (b === "" && a !== "") return -1;
      return a.localeCompare(b);
    })
    .map(([directory, dirFiles]) => ({
      directory,
      files: dirFiles.sort((a, b) => {
        const aName = a.newPath.slice(a.newPath.lastIndexOf("/") + 1);
        const bName = b.newPath.slice(b.newPath.lastIndexOf("/") + 1);
        return aName.localeCompare(bName);
      }),
    }));

  return sorted;
}

function getFileName(path: string): string {
  const lastSlash = path.lastIndexOf("/");
  return lastSlash >= 0 ? path.slice(lastSlash + 1) : path;
}

const changeTypeDotColor: Record<string, string> = {
  added: "bg-status-success-fg",
  deleted: "bg-status-error-fg",
  renamed: "bg-status-active-fg",
};

function FilesView({
  files,
  comments,
  onFileClick,
  onCommentClick,
  selectedCommit,
  activeFiles,
  viewedFiles,
}: {
  files: FileDiff[];
  comments: ReviewComment[];
  onFileClick: (filePath: string) => void;
  onCommentClick?: (commentId: string) => void;
  selectedCommit: string | null;
  activeFiles: FileDiff[];
  viewedFiles: Set<string>;
}) {
  const unresolvedCount = comments.filter((c) => !c.resolved && !c.parentCommentId).length;
  const resolvedCount = comments.filter((c) => c.resolved && !c.parentCommentId).length;
  const activeFilePaths = new Set(activeFiles.map((f) => f.newPath));

  const directoryGroups = useMemo(() => groupFilesByDirectory(files), [files]);

  const viewedCount = files.filter((f) => viewedFiles.has(f.newPath)).length;
  const totalCount = files.length;
  const progressPercent = totalCount > 0 ? (viewedCount / totalCount) * 100 : 0;

  return (
    <div className="space-y-4">
      {/* Review progress */}
      {totalCount > 0 && (
        <div className="space-y-1.5">
          <h4 className="text-[10px] font-semibold text-muted-foreground uppercase tracking-wider">
            Review Progress
          </h4>
          <div className="h-1 rounded-full bg-muted w-full">
            <div
              className="h-full rounded-full bg-status-success-fg transition-all duration-300"
              style={{ width: `${progressPercent}%` }}
            />
          </div>
          <span className="text-[10px] text-muted-foreground">
            {viewedCount}/{totalCount} files viewed
          </span>
        </div>
      )}

      {/* Discussions — individual threads */}
      {comments.length > 0 && (
        <div className="space-y-1.5">
          <h4 className="text-[10px] font-semibold text-muted-foreground uppercase tracking-wider flex items-center justify-between">
            <span>Discussions</span>
            <span className="flex items-center gap-2 font-normal normal-case">
              {unresolvedCount > 0 && (
                <span className="flex items-center gap-0.5 text-status-warning-fg">
                  <Circle className="h-2.5 w-2.5" />
                  {unresolvedCount}
                </span>
              )}
              {resolvedCount > 0 && (
                <span className="flex items-center gap-0.5 text-status-success-fg">
                  <CheckCircle2 className="h-2.5 w-2.5" />
                  {resolvedCount}
                </span>
              )}
            </span>
          </h4>
          <div className="space-y-0.5">
            {comments
              .filter((c) => !c.parentCommentId)
              .map((thread) => {
                const replyCount = comments.filter(
                  (c) => c.parentCommentId === thread.id,
                ).length;
                return (
                  <button
                    key={thread.id}
                    className={`
                      flex w-full flex-col gap-0.5 rounded px-2 py-1.5 text-left
                      transition-colors hover:bg-accent/50
                      ${thread.resolved ? "opacity-50" : ""}
                    `}
                    onClick={() => onCommentClick ? onCommentClick(thread.id) : onFileClick(thread.filePath)}
                  >
                    <div className="flex items-center gap-1.5 w-full min-w-0">
                      {thread.resolved ? (
                        <CheckCircle2 className="h-3 w-3 text-status-success-fg shrink-0" />
                      ) : (
                        <MessageSquare className="h-3 w-3 text-status-warning-fg shrink-0" />
                      )}
                      <span className="text-[10px] font-mono text-muted-foreground truncate">
                        {getFileName(thread.filePath)}:{thread.lineNumber}
                      </span>
                      {replyCount > 0 && (
                        <span className="text-[9px] text-muted-foreground/70 shrink-0 ml-auto">
                          {replyCount}
                        </span>
                      )}
                    </div>
                    <span className="text-[11px] text-foreground/80 truncate pl-[18px]">
                      {thread.body.length > 60
                        ? thread.body.slice(0, 57) + "..."
                        : thread.body}
                    </span>
                  </button>
                );
              })}
          </div>
        </div>
      )}

      {/* Directory-grouped file tree */}
      <div>
        <h4 className="text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-1.5">
          Files
          {selectedCommit && (
            <span className="font-normal ml-1 normal-case">
              ({activeFiles.length} in commit)
            </span>
          )}
        </h4>
        {directoryGroups.map((group) => (
          <div key={group.directory}>
            {/* Directory header */}
            {group.directory && (
              <div className="text-[10px] font-mono text-muted-foreground/70 mt-2 first:mt-0 px-2 py-0.5 flex items-center gap-1">
                <FolderOpen className="h-3 w-3 shrink-0" />
                <span className="truncate">{group.directory}</span>
              </div>
            )}
            {/* Files in directory */}
            <div className="space-y-0.5">
              {group.files.map((file) => {
                const fileCommentCount = comments.filter(
                  (c) => c.filePath === file.newPath && !c.parentCommentId,
                ).length;
                const isInView = activeFilePaths.has(file.newPath);
                const dimmed = selectedCommit && !isInView;
                const isViewed = viewedFiles.has(file.newPath);
                const dotColor = changeTypeDotColor[file.changeType];

                return (
                  <button
                    key={file.newPath}
                    className={`
                      flex w-full items-center gap-1.5 rounded py-1 text-left text-[11px]
                      hover:bg-accent/50 transition-colors group
                      ${group.directory ? "pl-4 pr-2" : "px-2"}
                      ${dimmed ? "opacity-35" : ""}
                    `}
                    onClick={() => onFileClick(file.newPath)}
                  >
                    {isViewed ? (
                      <CheckCircle2 className="h-3 w-3 text-status-success-fg shrink-0" />
                    ) : (
                      <FileCode className="h-3 w-3 text-muted-foreground shrink-0" />
                    )}
                    {dotColor && (
                      <span className={`h-1.5 w-1.5 rounded-full shrink-0 ${dotColor}`} />
                    )}
                    <span className="truncate flex-1 font-mono">
                      {getFileName(file.newPath)}
                    </span>
                    <span className="flex items-center gap-1 shrink-0">
                      {fileCommentCount > 0 && (
                        <span className="flex items-center gap-0.5 text-muted-foreground">
                          <MessageSquare className="h-2.5 w-2.5" />
                          {fileCommentCount}
                        </span>
                      )}
                      {file.additions > 0 && (
                        <span className="text-diff-add-fg text-[10px]">
                          <Plus className="h-2.5 w-2.5 inline" />
                          {file.additions}
                        </span>
                      )}
                      {file.deletions > 0 && (
                        <span className="text-diff-remove-fg text-[10px]">
                          <Minus className="h-2.5 w-2.5 inline" />
                          {file.deletions}
                        </span>
                      )}
                    </span>
                  </button>
                );
              })}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ─── Commits View ─────────────────────────────────────── */

function CommitsView({
  commits,
  selectedCommit,
  onSelectCommit,
}: {
  commits: CommitInfo[];
  selectedCommit: string | null;
  onSelectCommit: (hash: string | null) => void;
}) {
  if (commits.length === 0) {
    return (
      <div className="flex items-center justify-center h-20 text-xs text-muted-foreground">
        No commits
      </div>
    );
  }

  return (
    <div className="space-y-0.5">
      <h4 className="text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-1.5">
        Commits
      </h4>

      {/* "All changes" — only when >1 commit */}
      {commits.length > 1 && (
        <button
          onClick={() => onSelectCommit(null)}
          className={`
            flex w-full items-center gap-2 rounded px-2 py-1.5 text-left text-[11px]
            transition-colors
            ${selectedCommit === null
              ? "bg-primary/10 text-primary"
              : "text-muted-foreground hover:text-foreground hover:bg-accent/50"
            }
          `}
        >
          <Layers className="h-3 w-3 shrink-0" />
          <span className="font-medium">All changes</span>
          <span className="ml-auto text-[10px] opacity-70">
            {commits.length} commits
          </span>
        </button>
      )}

      {/* Commit list */}
      {commits.map((commit) => {
        const isActive = selectedCommit === commit.hash;
        return (
          <button
            key={commit.hash}
            onClick={() => onSelectCommit(commit.hash)}
            className={`
              flex w-full flex-col gap-0.5 rounded px-2 py-1.5 text-left
              transition-colors
              ${isActive
                ? "bg-primary/10 text-primary"
                : "text-foreground hover:bg-accent/50"
              }
            `}
          >
            {/* Hash + stats */}
            <div className="flex items-center gap-1.5 w-full">
              <GitCommitHorizontal className={`h-3 w-3 shrink-0 ${isActive ? "text-primary" : "text-muted-foreground"}`} />
              <span className="font-mono text-[11px] font-medium">
                {commit.shortHash}
              </span>
              <span className="ml-auto flex items-center gap-1.5 text-[10px] shrink-0">
                <span className="text-muted-foreground">{commit.filesChanged}f</span>
                <span className="text-diff-add-fg">+{commit.insertions}</span>
                <span className="text-diff-remove-fg">&minus;{commit.deletions}</span>
              </span>
            </div>

            {/* Message */}
            <span className={`text-[11px] truncate pl-[18px] ${isActive ? "text-primary/80" : "text-muted-foreground"}`}>
              {truncateMessage(commit.message)}
            </span>
          </button>
        );
      })}
    </div>
  );
}

/* ─── Helpers ──────────────────────────────────────────── */

function truncateMessage(msg: string): string {
  const firstLine = msg.split("\n")[0];
  return firstLine.length > 50 ? firstLine.slice(0, 47) + "..." : firstLine;
}
