import { File, FileCode, FileImage, FileText, Folder } from 'lucide-react';
import { useState } from 'react';
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom';

import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';
import { useGitBlob } from '@/hooks/repo/useGitBlob';
import { useGitTree } from '@/hooks/repo/useGitTree';
import { useRepo } from '@/hooks/repo/useRepo';
import { useRepoBranches } from '@/hooks/repo/useRepoBranches';
import { cn } from '@/lib/utils';

export function RepoCodePage() {
  const { workspaceName = '', repoName = '' } = useParams();
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();

  const currentBranch = searchParams.get('branch') || '';
  const currentPath = searchParams.get('path') || '';

  const { data: repo } = useRepo(workspaceName, repoName);
  const { data: branches } = useRepoBranches(workspaceName, repoName);
  const { data: tree, isLoading } = useGitTree(
    workspaceName,
    repoName,
    currentBranch || repo?.default_branch || 'HEAD',
    currentPath || undefined,
  );

  const [showBranchSelector, setShowBranchSelector] = useState(false);

  const updateParams = (updates: Record<string, string | null>) => {
    const next = new URLSearchParams(searchParams);
    for (const [key, value] of Object.entries(updates)) {
      if (value === null || value === '') next.delete(key);
      else next.set(key, value);
    }
    setSearchParams(next, { replace: true });
  };

  const effectiveBranch = currentBranch || repo?.default_branch || '';
  const pathParts = currentPath ? currentPath.split('/').filter(Boolean) : [];

  const breadcrumbs = [
    { label: repoName, path: '' },
    ...pathParts.map((part, idx) => ({
      label: part,
      path: pathParts.slice(0, idx + 1).join('/'),
    })),
  ];

  const entries = tree?.entries ?? [];
  const dirs = entries.filter((e) => e.type === 2).sort((a, b) => a.name.localeCompare(b.name));
  const files = entries.filter((e) => e.type !== 2).sort((a, b) => a.name.localeCompare(b.name));
  const sortedEntries = [...dirs, ...files];

  return (
    <div className="space-y-4">
      <div className="flex items-center gap-2">
        <div className="relative">
          <Button
            variant="outline"
            size="sm"
            onClick={() => setShowBranchSelector(!showBranchSelector)}
          >
            {effectiveBranch || 'Select branch'}
          </Button>
          {showBranchSelector && (
            <div className="absolute top-full left-0 z-10 mt-1 w-48 rounded-lg border border-border bg-card shadow-lg">
              <div className="max-h-64 overflow-y-auto p-1">
                {branches?.map((branch: { name: string; id?: string }) => (
                  <button
                    key={branch.id || branch.name}
                    type="button"
                    className={cn(
                      'w-full rounded px-3 py-1.5 text-left text-[13px] transition-colors',
                      branch.name === effectiveBranch
                        ? 'bg-primary/10 text-primary'
                        : 'text-foreground hover:bg-muted',
                    )}
                    onClick={() => {
                      updateParams({ branch: branch.name });
                      setShowBranchSelector(false);
                    }}
                  >
                    {branch.name}
                  </button>
                ))}
              </div>
            </div>
          )}
        </div>
        <div className="flex items-center gap-1 text-[13px]">
          {breadcrumbs.map((crumb, idx) => (
            <span key={crumb.path || `root-${idx}`} className="flex items-center gap-1">
              {idx > 0 && <span className="text-muted-foreground">/</span>}
              <button
                type="button"
                className="text-foreground hover:text-primary hover:underline"
                onClick={() => updateParams({ path: crumb.path || null })}
              >
                {crumb.label}
              </button>
            </span>
          ))}
        </div>
        <Link
          to={`/${workspaceName}/repos/${repoName}/commits?branch=${effectiveBranch}`}
          className="ml-auto text-[12px] text-muted-foreground hover:text-foreground"
        >
          History
        </Link>
      </div>

      <div className="overflow-hidden rounded-lg border border-border">
        {isLoading ? (
          <div className="flex items-center justify-center py-12">
            <Spinner />
          </div>
        ) : sortedEntries.length > 0 ? (
          <div className="divide-y divide-border">
            {currentPath && (
              <button
                type="button"
                className="flex w-full items-center gap-2 px-4 py-2 text-left text-[13px] transition-colors hover:bg-muted"
                onClick={() => {
                  const parentPath = pathParts.slice(0, -1).join('/');
                  updateParams({ path: parentPath || null });
                }}
              >
                <Folder className="size-4 text-muted-foreground" />
                <span className="text-muted-foreground">..</span>
              </button>
            )}
            {sortedEntries.map((entry) => (
              <button
                key={entry.path}
                type="button"
                className="flex w-full items-center gap-2 px-4 py-2 text-left text-[13px] transition-colors hover:bg-muted"
                onClick={() => {
                  if (entry.type === 2) {
                    updateParams({ path: entry.path });
                  } else {
                    const params = new URLSearchParams();
                    if (effectiveBranch) params.set('branch', effectiveBranch);
                    params.set('blob', entry.path);
                    navigate(`/${workspaceName}/repos/${repoName}/blob?${params}`);
                  }
                }}
              >
                {entry.type === 2 ? (
                  <Folder className="size-4 text-blue-500" />
                ) : (
                  <FileIcon filename={entry.name} />
                )}
                <span className="flex-1 text-foreground">{entry.name}</span>
                {entry.size > 0 && entry.type !== 2 && (
                  <span className="text-[11px] text-muted-foreground">
                    {formatSize(entry.size)}
                  </span>
                )}
              </button>
            ))}
          </div>
        ) : (
          <div className="py-12 text-center text-[13px] text-muted-foreground">
            This directory is empty
          </div>
        )}
      </div>

      <ReadmePreview
        workspaceName={workspaceName}
        repoName={repoName}
        branch={effectiveBranch}
        files={files}
      />
    </div>
  );
}

function FileIcon({ filename }: { filename: string }) {
  const ext = filename.split('.').pop()?.toLowerCase();
  if (['md', 'txt', 'rst'].includes(ext || '')) {
    return <FileText className="size-4 text-muted-foreground" />;
  }
  if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'].includes(ext || '')) {
    return <FileImage className="size-4 text-muted-foreground" />;
  }
  if (['ts', 'tsx', 'js', 'jsx', 'py', 'rs', 'go', 'java', 'cpp', 'c', 'h'].includes(ext || '')) {
    return <FileCode className="size-4 text-muted-foreground" />;
  }
  return <File className="size-4 text-muted-foreground" />;
}

function formatSize(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

function ReadmePreview({
  workspaceName,
  repoName,
  branch,
  files,
}: {
  workspaceName: string;
  repoName: string;
  branch: string;
  files: Array<{ name: string; path: string }>;
}) {
  const readmeFile = files.find((f) =>
    ['README.md', 'readme.md', 'README', 'README.txt'].includes(f.name),
  );

  const { data: blob } = useGitBlob(
    readmeFile ? workspaceName : null,
    readmeFile ? repoName : null,
    readmeFile ? branch : null,
    readmeFile ? readmeFile.path : null,
  );

  if (!readmeFile || !blob) return null;

  const content = new TextDecoder().decode(new Uint8Array(blob.data));

  return (
    <div className="overflow-hidden rounded-lg border border-border">
      <div className="flex items-center justify-between border-b border-border bg-muted/30 px-4 py-2">
        <h3 className="text-[13px] font-semibold text-foreground">{readmeFile.name}</h3>
        <Link
          to={`/${workspaceName}/repos/${repoName}/blob?branch=${branch}&blob=${readmeFile.path}`}
          className="text-[11px] text-primary hover:underline"
        >
          View raw
        </Link>
      </div>
      <div className="max-h-96 overflow-y-auto p-4">
        <pre className="whitespace-pre-wrap text-[13px] text-foreground">{content}</pre>
      </div>
    </div>
  );
}
