'use client';

import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { DiffView } from '@cockpit/feature-explorer';
import { GitFileTree, buildGitFileTree, collectGitTreeDirPaths, type GitFileNode } from './GitFileTree';
import { BrowserRuntime } from '@cockpit/effect-runtime';
import { fetchCommitDiff } from './effect/gitClient';
import { formatAsHumanReadable } from './toolCallUtils';
import { useJsonSearch, JsonSearchBar } from '@cockpit/shared-ui';

// Types
export interface CommitInfo {
  hash: string;
  shortHash: string;
  author: string;
  authorEmail: string;
  date: string;
  subject: string;
  body: string;
  relativeDate?: string;
  time?: number; // Unix timestamp (for blame)
}

interface FileChange {
  path: string;
  status: 'added' | 'modified' | 'deleted' | 'renamed';
  oldPath?: string;
  additions: number;
  deletions: number;
}

interface FileDiff {
  oldContent: string;
  newContent: string;
  filePath: string;
  isNew: boolean;
  isDeleted: boolean;
}

// Format date time for display (e.g., "01-15 14:30" or "2024-01-15 14:30")
function formatDateTime(dateStr: string): string {
  const date = new Date(dateStr);
  const now = new Date();
  const isThisYear = date.getFullYear() === now.getFullYear();

  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  const hours = String(date.getHours()).padStart(2, '0');
  const minutes = String(date.getMinutes()).padStart(2, '0');

  if (isThisYear) {
    return `${month}-${day} ${hours}:${minutes}`;
  }
  return `${date.getFullYear()}-${month}-${day} ${hours}:${minutes}`;
}

// Main component props
interface CommitDetailPanelProps {
  isOpen: boolean;
  onClose: () => void;
  commit: CommitInfo | null;
  cwd: string;
  embedded?: boolean; // Embedded mode, no Modal wrapper or title bar
  initialFilePath?: string; // Initially selected file path
  onContentSearch?: (query: string) => void; // Selected text → project-wide search
}

export function CommitDetailPanel({ isOpen, onClose, commit, cwd, embedded = false, initialFilePath, onContentSearch }: CommitDetailPanelProps) {
  const { t } = useTranslation();
  const [files, setFiles] = useState<FileChange[]>([]);
  const [fileTree, setFileTree] = useState<GitFileNode<unknown>[]>([]);
  const [expandedPaths, setExpandedPaths] = useState<Set<string>>(new Set());
  const [selectedFile, setSelectedFile] = useState<FileChange | null>(null);
  const [fileDiff, setFileDiff] = useState<FileDiff | null>(null);
  const [isLoadingFiles, setIsLoadingFiles] = useState(false);
  const [isLoadingDiff, setIsLoadingDiff] = useState(false);
  const [jsonPreview, setJsonPreview] = useState<{ content: string; filePath: string } | null>(null);
  const commitPreRef = useRef<HTMLPreElement>(null);
  const commitJsonSearch = useJsonSearch(commitPreRef);

  // ESC / Cmd+F
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'f' && jsonPreview) {
        e.preventDefault();
        commitJsonSearch.open();
        return;
      }
      if (e.key === 'Escape') {
        if (commitJsonSearch.isVisible) {
          commitJsonSearch.close();
          return;
        }
        if (jsonPreview) {
          setJsonPreview(null);
          return;
        }
        onClose();
      }
    };
    if (isOpen) {
      document.addEventListener('keydown', handleKeyDown);
      return () => document.removeEventListener('keydown', handleKeyDown);
    }
  }, [isOpen, onClose, jsonPreview, commitJsonSearch]);

  // Load files when commit changes
  useEffect(() => {
    if (!isOpen || !commit) return;

    queueMicrotask(() => {
      setFiles([]);
      setFileTree([]);
      setSelectedFile(null);
      setFileDiff(null);
      setIsLoadingFiles(true);
    });

    BrowserRuntime.runPromiseExit(fetchCommitDiff(cwd, commit.hash)).then((exit) => {
      if (exit._tag === 'Success') {
        const fileList: FileChange[] = (exit.value.files ?? []) as FileChange[];
        setFiles(fileList);
        const tree = buildGitFileTree(fileList);
        setFileTree(tree);
        setExpandedPaths(new Set(collectGitTreeDirPaths(tree)));

        // If initialFilePath is set, auto-select the corresponding file
        if (initialFilePath && fileList.length > 0) {
          const matchedFile = fileList.find(f => f.path === initialFilePath);
          if (matchedFile) {
            setTimeout(() => {
              setSelectedFile(matchedFile);
              // Load diff
              BrowserRuntime.runPromiseExit(
                fetchCommitDiff(cwd, commit.hash, matchedFile.path)
              ).then((diffExit) => {
                if (diffExit._tag === 'Success') {
                  setFileDiff(diffExit.value as unknown as FileDiff);
                } else {
                  console.error(diffExit.cause);
                }
              });
            }, 0);
          }
        }
      } else {
        console.error(exit.cause);
      }
      setIsLoadingFiles(false);
    });
  }, [isOpen, commit, cwd, initialFilePath]);

  // Load diff when file selected
  const handleSelectFile = useCallback((file: FileChange) => {
    if (!commit) return;
    setSelectedFile(file);
    setIsLoadingDiff(true);
    BrowserRuntime.runPromiseExit(fetchCommitDiff(cwd, commit.hash, file.path)).then((exit) => {
      if (exit._tag === 'Success') {
        setFileDiff(exit.value as unknown as FileDiff);
      } else {
        console.error(exit.cause);
      }
      setIsLoadingDiff(false);
    });
  }, [cwd, commit]);

  // Toggle directory expand/collapse
  const handleToggle = useCallback((path: string) => {
    setExpandedPaths(prev => {
      const next = new Set(prev);
      if (next.has(path)) {
        next.delete(path);
      } else {
        next.add(path);
      }
      return next;
    });
  }, []);

  // Format display date
  const displayDate = useMemo(() => {
    if (!commit) return '';
    if (commit.date) {
      return formatDateTime(commit.date);
    }
    if (commit.time) {
      return new Date(commit.time * 1000).toLocaleString();
    }
    return '';
  }, [commit]);

  if (!isOpen || !commit) return null;

  // Content section (shared between embedded and modal modes)
  const content = (
    <div className="flex-1 flex flex-col overflow-hidden">
      {/* Commit info header */}
      <div className="px-4 py-3 border-b border-border bg-secondary flex-shrink-0">
        <div className="text-sm font-medium text-foreground mb-2">
          {commit.subject}
        </div>
        {commit.body && (
          <div className="text-xs text-muted-foreground whitespace-pre-wrap mb-3 max-h-32 overflow-y-auto border-l-2 border-border pl-3">
            {commit.body}
          </div>
        )}
        <div className="flex flex-wrap gap-4 text-xs text-muted-foreground">
          <div className="flex items-center gap-1">
            <span className="text-slate-9">{t('commitDetail.hash')}</span>
            <span className="font-mono bg-accent px-1.5 py-0.5 rounded">
              {commit.hash}
            </span>
          </div>
          <div className="flex items-center gap-1">
            <span className="text-slate-9">{t('commitDetail.author')}</span>
            <span>{commit.author}</span>
            <span className="text-slate-9">&lt;{commit.authorEmail}&gt;</span>
          </div>
          <div className="flex items-center gap-1">
            <span className="text-slate-9">{t('commitDetail.date')}</span>
            <span>{displayDate}</span>
            {commit.relativeDate && (
              <span className="text-slate-9">({commit.relativeDate})</span>
            )}
          </div>
          <div className="flex items-center gap-1">
            <span className="text-slate-9">{t('commitDetail.files')}</span>
            <span>{t('commitDetail.nChanges', { count: files.length })}</span>
          </div>
        </div>
      </div>

      {/* File tree + Diff container */}
      <div className="flex-1 flex overflow-hidden">
        {/* File tree */}
        <div className="w-72 flex-shrink-0 border-r border-border overflow-y-auto overflow-x-hidden">
          {isLoadingFiles ? (
            <div className="p-4 text-center text-muted-foreground text-sm">{t('commitDetail.loadingFiles')}</div>
          ) : (
            <GitFileTree
              files={fileTree}
              selectedPath={selectedFile?.path || null}
              expandedPaths={expandedPaths}
              onSelect={(node) => node.file && handleSelectFile(node.file as FileChange)}
              onToggle={handleToggle}
              cwd={cwd}
              showChanges={true}
              emptyMessage={t('commitDetail.noFileChanges')}
              className="py-1"
            />
          )}
        </div>

        {/* Diff view */}
        <div className="flex-1 overflow-hidden">
          {isLoadingDiff ? (
            <div className="h-full flex items-center justify-center text-muted-foreground text-sm">{t('commitDetail.loadingDiff')}</div>
          ) : fileDiff ? (
            <DiffView
              oldContent={fileDiff.oldContent}
              newContent={fileDiff.newContent}
              filePath={fileDiff.filePath}
              isNew={fileDiff.isNew}
              isDeleted={fileDiff.isDeleted}
              cwd={cwd}
              enableComments={true}
              onPreview={
                !fileDiff.isDeleted && fileDiff.filePath.endsWith('.json')
                  ? () => setJsonPreview({ content: fileDiff.newContent, filePath: fileDiff.filePath })
                  : undefined
              }
              previewLabel={t('common.readable')}
              onContentSearch={onContentSearch}
            />
          ) : (
            <div className="h-full flex items-center justify-center text-muted-foreground text-sm">
              {t('commitDetail.selectFileToView')}
            </div>
          )}
        </div>
      </div>
    </div>
  );

  const jsonPreviewModal = jsonPreview && (
    <div className="absolute inset-0 z-50 flex items-center justify-center bg-black/50" onClick={() => setJsonPreview(null)}>
      <div
        className="bg-card rounded-lg shadow-xl w-full max-w-[90%] h-[90%] flex flex-col"
        onClick={(e) => e.stopPropagation()}
      >
        <div className="flex items-center justify-between px-4 py-2 border-b border-border flex-shrink-0">
          <span className="text-sm text-muted-foreground font-mono truncate">{jsonPreview.filePath}</span>
          <button
            onClick={() => setJsonPreview(null)}
            className="p-1 text-muted-foreground hover:text-foreground hover:bg-accent rounded transition-colors"
          >
            <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
            </svg>
          </button>
        </div>
        <JsonSearchBar search={commitJsonSearch} />
        <div className="flex-1 overflow-auto px-6 py-4 bg-[#0d1117]">
          <pre ref={commitPreRef} className="whitespace-pre-wrap break-words font-mono" style={{ fontSize: '0.8125rem', lineHeight: '1.5' }}>
            {formatAsHumanReadable(jsonPreview.content)}
          </pre>
        </div>
      </div>
    </div>
  );

  // Embedded mode: no Modal wrapper or title bar, but has a close button in top-right
  if (embedded) {
    return (
      <div className="bg-card w-full h-full flex flex-col relative">
        <button
          onClick={onClose}
          className="absolute top-2 right-2 z-10 p-1 text-slate-9 hover:text-foreground hover:bg-accent rounded transition-colors"
          title={t('common.close')}
        >
          <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
          </svg>
        </button>
        {content}
        {jsonPreviewModal}
      </div>
    );
  }

  // Modal mode
  return (
    <div className="fixed inset-0 z-[60] bg-black/50" onClick={onClose}>
      <div
        className="bg-card w-full h-full flex flex-col"
        onClick={e => e.stopPropagation()}
      >
        {/* Header */}
        <div className="flex items-center justify-between px-4 py-3 border-b border-border">
          <h3 className="text-sm font-medium text-foreground">{t('commitDetail.title')}</h3>
          <button
            onClick={onClose}
            className="p-1 text-slate-9 hover:text-foreground hover:bg-accent rounded transition-colors"
          >
            <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
            </svg>
          </button>
        </div>

        {/* Content */}
        {content}
        {jsonPreviewModal}
      </div>
    </div>
  );
}
