import { ArrowLeft, Code, Copy, Download, GitCommit } from 'lucide-react';
import { useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { Link, useParams } from 'react-router-dom';

import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';
import { useGitBlame } from '@/hooks/repo/useGitBlame';
import { useGitBlob } from '@/hooks/repo/useGitBlob';
import { useRepo } from '@/hooks/repo/useRepo';

export function RepoBlobPage() {
  const { workspaceName = '', repoName = '' } = useParams();
  const [searchParams] = useSearchParams();

  const branch = searchParams.get('branch') || '';
  const filePath = searchParams.get('blob') || '';

  const { data: repo } = useRepo(workspaceName, repoName);
  const { data: blob, isLoading } = useGitBlob(
    workspaceName,
    repoName,
    branch || (repo?.default_branch ?? null),
    filePath || null,
  );

  const [view, setView] = useState<'code' | 'blame'>('code');

  const effectiveBranch = branch || repo?.default_branch || '';
  const fileName = filePath.split('/').pop() || '';

  if (isLoading) {
    return (
      <div className="flex items-center justify-center py-12">
        <Spinner />
      </div>
    );
  }

  if (!blob) {
    return (
      <div className="py-12 text-center">
        <p className="text-[13px] text-muted-foreground">File not found</p>
        <Link
          to={`/${workspaceName}/repos/${repoName}?branch=${effectiveBranch}`}
          className="mt-2 inline-block text-[13px] text-primary hover:underline"
        >
          Back to code
        </Link>
      </div>
    );
  }

  const content = blob.binary ? null : new TextDecoder().decode(new Uint8Array(blob.data));
  const lines = content ? content.split('\n') : [];

  const handleCopy = () => {
    if (content) navigator.clipboard.writeText(content);
  };

  const handleDownload = () => {
    if (!content) return;
    const blobObj = new Blob([content], { type: 'text/plain' });
    const url = URL.createObjectURL(blobObj);
    const a = document.createElement('a');
    a.href = url;
    a.download = fileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div className="space-y-4">
      <div className="flex items-center gap-2">
        <Link
          to={`/${workspaceName}/repos/${repoName}?branch=${effectiveBranch}`}
          className="flex items-center gap-1 text-[13px] text-muted-foreground hover:text-foreground"
        >
          <ArrowLeft className="size-3.5" />
          Back
        </Link>
        <span className="text-[13px] text-muted-foreground">/</span>
        <span className="text-[13px] font-medium text-foreground">{filePath}</span>
      </div>

      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2 text-[12px] text-muted-foreground">
          <span>{lines.length} lines</span>
          <span>·</span>
          <span>{formatSize(blob.size)}</span>
        </div>
        <div className="flex items-center gap-1">
          <Button
            variant={view === 'code' ? 'default' : 'outline'}
            size="sm"
            onClick={() => setView('code')}
          >
            <Code className="size-3.5" />
            Code
          </Button>
          <Button
            variant={view === 'blame' ? 'default' : 'outline'}
            size="sm"
            onClick={() => setView('blame')}
          >
            <GitCommit className="size-3.5" />
            Blame
          </Button>
          <Button variant="outline" size="sm" onClick={handleCopy}>
            <Copy className="size-3.5" />
          </Button>
          <Button variant="outline" size="sm" onClick={handleDownload}>
            <Download className="size-3.5" />
          </Button>
        </div>
      </div>

      {blob.binary ? (
        <div className="rounded-lg border border-border p-8 text-center">
          <p className="text-[13px] text-muted-foreground">Binary file not shown</p>
        </div>
      ) : view === 'code' ? (
        <div className="overflow-hidden rounded-lg border border-border bg-card">
          <div className="overflow-x-auto">
            <table className="w-full">
              <tbody>
                {lines.map((line, idx) => (
                  <tr key={idx} className="border-b border-border/50 last:border-b-0">
                    <td className="select-none px-3 py-0.5 text-right text-[11px] text-muted-foreground/60">
                      {idx + 1}
                    </td>
                    <td className="px-3 py-0.5">
                      <pre className="text-[13px] text-foreground">{line}</pre>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      ) : (
        <BlameView
          workspaceName={workspaceName}
          repoName={repoName}
          branch={effectiveBranch}
          path={filePath}
        />
      )}
    </div>
  );
}

function BlameView({
  workspaceName,
  repoName,
  branch,
  path,
}: {
  workspaceName: string;
  repoName: string;
  branch: string;
  path: string;
}) {
  const { data: blame, isLoading } = useGitBlame(workspaceName, repoName, branch, path);

  if (isLoading) {
    return (
      <div className="flex items-center justify-center py-12">
        <Spinner />
      </div>
    );
  }

  if (!blame) {
    return <div className="py-12 text-center text-[13px] text-muted-foreground">No blame data</div>;
  }

  return (
    <div className="overflow-hidden rounded-lg border border-border bg-card">
      <div className="divide-y divide-border">
        {blame.hunks.map((hunk, idx) => {
          const commitMsg = hunk.commit?.subject || 'Unknown';
          const commitSha = hunk.commit?.abbreviated_oid || '';
          const lines = hunk.lines || [];

          return (
            <div key={idx}>
              <div className="border-b border-border/50 bg-muted/30 px-3 py-1.5 text-[11px] text-muted-foreground">
                <code className="mr-2">{commitSha}</code>
                {commitMsg}
              </div>
              {lines.map((line, lineIdx) => (
                <div key={lineIdx} className="flex border-b border-border/30 last:border-b-0">
                  <div className="w-12 shrink-0 select-none px-2 py-0.5 text-right text-[11px] text-muted-foreground/60">
                    {line.final_line}
                  </div>
                  <pre className="flex-1 px-3 py-0.5 text-[13px] text-foreground">
                    {new TextDecoder().decode(new Uint8Array(line.content))}
                  </pre>
                </div>
              ))}
            </div>
          );
        })}
      </div>
    </div>
  );
}

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`;
}
