import { useState, useEffect, useCallback } from 'react';
import { useParams, useSearchParams, useNavigate, useLocation, Link } from 'react-router-dom';
import { PackageArtifact, Package, PaginatedResponse, AccessLevel, Dependency, DependentInfo } from '../types';
import { listPackageArtifacts, getDownloadUrl, getPackage, getMyProjectAccess, getArtifactDependencies, getReverseDependencies, getEnsureFile, UnauthorizedError, ForbiddenError } from '../api';
import { Breadcrumb } from '../components/Breadcrumb';
import { Badge } from '../components/Badge';
import { SearchInput } from '../components/SearchInput';
import { FilterChip, FilterChipGroup } from '../components/FilterChip';
import { DataTable } from '../components/DataTable';
import { Pagination } from '../components/Pagination';
import { DragDropUpload, UploadResult } from '../components/DragDropUpload';
import { useAuth } from '../contexts/AuthContext';
import DependencyGraph from '../components/DependencyGraph';
import './Home.css';
import './PackagePage.css';

function formatBytes(bytes: number): string {
  if (bytes === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}

function CopyButton({ text }: { text: string }) {
  const [copied, setCopied] = useState(false);

  const handleCopy = async (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    await navigator.clipboard.writeText(text);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  };

  return (
    <button className="copy-btn" onClick={handleCopy} title="Copy to clipboard">
      {copied ? (
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
          <polyline points="20 6 9 17 4 12" />
        </svg>
      ) : (
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
          <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
          <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
        </svg>
      )}
    </button>
  );
}

function PackagePage() {
  const { projectName, packageName } = useParams<{ projectName: string; packageName: string }>();
  const navigate = useNavigate();
  const location = useLocation();
  const [searchParams, setSearchParams] = useSearchParams();
  const { user } = useAuth();

  const [pkg, setPkg] = useState<Package | null>(null);
  const [artifactsData, setArtifactsData] = useState<PaginatedResponse<PackageArtifact> | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [accessDenied, setAccessDenied] = useState(false);
  const [uploadSuccess, setUploadSuccess] = useState<string | null>(null);
  const [accessLevel, setAccessLevel] = useState<AccessLevel | null>(null);

  // UI state
  const [showUploadModal, setShowUploadModal] = useState(false);
  const [openMenuId, setOpenMenuId] = useState<string | null>(null);
  const [menuPosition, setMenuPosition] = useState<{ top: number; left: number } | null>(null);

  // Dependencies state
  const [selectedArtifact, setSelectedArtifact] = useState<PackageArtifact | null>(null);
  const [dependencies, setDependencies] = useState<Dependency[]>([]);
  const [depsLoading, setDepsLoading] = useState(false);
  const [depsError, setDepsError] = useState<string | null>(null);

  // Reverse dependencies state
  const [reverseDeps, setReverseDeps] = useState<DependentInfo[]>([]);
  const [reverseDepsLoading, setReverseDepsLoading] = useState(false);
  const [reverseDepsError, setReverseDepsError] = useState<string | null>(null);
  const [reverseDepsPage, setReverseDepsPage] = useState(1);
  const [reverseDepsTotal, setReverseDepsTotal] = useState(0);
  const [reverseDepsHasMore, setReverseDepsHasMore] = useState(false);

  // Dependency graph modal state
  const [showGraph, setShowGraph] = useState(false);

  // Dependencies modal state
  const [showDepsModal, setShowDepsModal] = useState(false);

  // Artifact ID modal state
  const [showArtifactIdModal, setShowArtifactIdModal] = useState(false);
  const [viewArtifactId, setViewArtifactId] = useState<string | null>(null);

  // Ensure file modal state
  const [showEnsureFile, setShowEnsureFile] = useState(false);
  const [ensureFileContent, setEnsureFileContent] = useState<string | null>(null);
  const [ensureFileLoading, setEnsureFileLoading] = useState(false);
  const [ensureFileError, setEnsureFileError] = useState<string | null>(null);
  const [ensureFileTagName, setEnsureFileTagName] = useState<string | null>(null);

  // Derived permissions
  const canWrite = accessLevel === 'write' || accessLevel === 'admin';

  // Detect system projects (convention: name starts with "_")
  const isSystemProject = projectName?.startsWith('_') ?? false;

  // Get params from URL
  // Valid sort fields for artifacts: created_at, size, original_name
  const page = parseInt(searchParams.get('page') || '1', 10);
  const search = searchParams.get('search') || '';
  const sort = searchParams.get('sort') || 'created_at';
  const order = (searchParams.get('order') || 'desc') as 'asc' | 'desc';

  const updateParams = useCallback(
    (updates: Record<string, string | undefined>) => {
      const newParams = new URLSearchParams(searchParams);
      Object.entries(updates).forEach(([key, value]) => {
        if (value === undefined || value === '' || (key === 'page' && value === '1')) {
          newParams.delete(key);
        } else {
          newParams.set(key, value);
        }
      });
      setSearchParams(newParams);
    },
    [searchParams, setSearchParams]
  );

  const loadData = useCallback(async () => {
    if (!projectName || !packageName) return;

    try {
      setLoading(true);
      setAccessDenied(false);
      const [pkgData, artifactsResult, accessResult] = await Promise.all([
        getPackage(projectName, packageName),
        listPackageArtifacts(projectName, packageName, { page, search, sort, order }),
        getMyProjectAccess(projectName),
      ]);
      setPkg(pkgData);
      setArtifactsData(artifactsResult);
      setAccessLevel(accessResult.access_level);
      setError(null);
    } catch (err) {
      if (err instanceof UnauthorizedError) {
        navigate('/login', { state: { from: location.pathname } });
        return;
      }
      if (err instanceof ForbiddenError) {
        setAccessDenied(true);
        setError('You do not have access to this package');
        setLoading(false);
        return;
      }
      setError(err instanceof Error ? err.message : 'Failed to load data');
    } finally {
      setLoading(false);
    }
  }, [projectName, packageName, page, search, sort, order, navigate, location.pathname]);

  useEffect(() => {
    loadData();
  }, [loadData]);

  // Auto-select artifact when artifacts are loaded (prefer first artifact)
  // Re-run when package changes to pick up new artifacts
  useEffect(() => {
    if (artifactsData?.items && artifactsData.items.length > 0) {
      // Fall back to first artifact
      setSelectedArtifact(artifactsData.items[0]);
      setDependencies([]);
    }
  }, [artifactsData, projectName, packageName]);

  // Fetch dependencies when selected tag changes
  const fetchDependencies = useCallback(async (artifactId: string) => {
    setDepsLoading(true);
    setDepsError(null);
    try {
      const result = await getArtifactDependencies(artifactId);
      setDependencies(result.dependencies);
    } catch (err) {
      setDepsError(err instanceof Error ? err.message : 'Failed to load dependencies');
      setDependencies([]);
    } finally {
      setDepsLoading(false);
    }
  }, []);

  useEffect(() => {
    if (selectedArtifact) {
      fetchDependencies(selectedArtifact.id);
    }
  }, [selectedArtifact, fetchDependencies]);

  // Fetch reverse dependencies
  const fetchReverseDeps = useCallback(async (pageNum: number = 1) => {
    if (!projectName || !packageName) return;

    setReverseDepsLoading(true);
    setReverseDepsError(null);
    try {
      const result = await getReverseDependencies(projectName, packageName, { page: pageNum, limit: 10 });
      setReverseDeps(result.dependents);
      setReverseDepsTotal(result.pagination.total);
      setReverseDepsHasMore(result.pagination.has_more);
      setReverseDepsPage(pageNum);
    } catch (err) {
      setReverseDepsError(err instanceof Error ? err.message : 'Failed to load reverse dependencies');
      setReverseDeps([]);
    } finally {
      setReverseDepsLoading(false);
    }
  }, [projectName, packageName]);

  useEffect(() => {
    if (projectName && packageName && !loading) {
      fetchReverseDeps(1);
    }
  }, [projectName, packageName, loading, fetchReverseDeps]);

  // Fetch ensure file for a specific version or artifact
  const fetchEnsureFileForRef = useCallback(async (ref: string) => {
    if (!projectName || !packageName) return;

    setEnsureFileTagName(ref);
    setEnsureFileLoading(true);
    setEnsureFileError(null);
    try {
      const content = await getEnsureFile(projectName, packageName, ref);
      setEnsureFileContent(content);
      setShowEnsureFile(true);
    } catch (err) {
      setEnsureFileError(err instanceof Error ? err.message : 'Failed to load ensure file');
      setShowEnsureFile(true);
    } finally {
      setEnsureFileLoading(false);
    }
  }, [projectName, packageName]);

  // Fetch ensure file for selected artifact
  const fetchEnsureFile = useCallback(async () => {
    if (!selectedArtifact) return;
    const version = getArtifactVersion(selectedArtifact);
    const ref = version || `artifact:${selectedArtifact.id}`;
    fetchEnsureFileForRef(ref);
  }, [selectedArtifact, fetchEnsureFileForRef]);

  // Keyboard navigation - go back with backspace
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Backspace' && !['INPUT', 'TEXTAREA'].includes((e.target as HTMLElement).tagName)) {
        e.preventDefault();
        navigate(`/project/${projectName}`);
      }
    };
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [navigate, projectName]);

  const handleUploadComplete = useCallback((results: UploadResult[]) => {
    const count = results.length;
    const message = count === 1
      ? `Uploaded successfully! Artifact ID: ${results[0].artifact_id}`
      : `${count} files uploaded successfully!`;
    setUploadSuccess(message);
    loadData();
    
    // Auto-dismiss success message after 5 seconds
    setTimeout(() => setUploadSuccess(null), 5000);
  }, [loadData]);

  const handleUploadError = useCallback((errorMsg: string) => {
    setError(errorMsg);
  }, []);

  const handleSearchChange = (value: string) => {
    updateParams({ search: value, page: '1' });
  };

  const handleSortChange = (columnKey: string) => {
    const newOrder = columnKey === sort ? (order === 'asc' ? 'desc' : 'asc') : 'asc';
    updateParams({ sort: columnKey, order: newOrder, page: '1' });
  };

  const handlePageChange = (newPage: number) => {
    updateParams({ page: String(newPage) });
  };

  const clearFilters = () => {
    setSearchParams({});
  };

  const hasActiveFilters = search !== '';
  const artifacts = artifactsData?.items || [];
  const pagination = artifactsData?.pagination;

  const handleArtifactSelect = (artifact: PackageArtifact) => {
    setSelectedArtifact(artifact);
  };

  const handleMenuOpen = (e: React.MouseEvent, artifactId: string) => {
    e.stopPropagation();
    if (openMenuId === artifactId) {
      setOpenMenuId(null);
      setMenuPosition(null);
    } else {
      const rect = e.currentTarget.getBoundingClientRect();
      setMenuPosition({ top: rect.bottom + 4, left: rect.right - 180 });
      setOpenMenuId(artifactId);
    }
  };

  // Helper to get version from artifact - prefer direct version field, fallback to metadata
  const getArtifactVersion = (a: PackageArtifact): string | null => {
    return a.version || (a.format_metadata?.version as string) || null;
  };

  // Helper to get download ref - prefer version, fallback to artifact ID
  const getDownloadRef = (a: PackageArtifact): string => {
    const version = getArtifactVersion(a);
    return version || `artifact:${a.id}`;
  };

  // System projects show Version first, regular projects show Tag first
  const columns = isSystemProject
    ? [
        // System project columns: Version first, then Filename
        {
          key: 'version',
          header: 'Version',
          // version is from format_metadata, not a sortable DB field
          render: (a: PackageArtifact) => (
            <strong
              className={`tag-name-link ${selectedArtifact?.id === a.id ? 'selected' : ''}`}
              onClick={() => handleArtifactSelect(a)}
              style={{ cursor: 'pointer' }}
            >
              <span className="version-badge">{getArtifactVersion(a) || a.id.slice(0, 12)}</span>
            </strong>
          ),
        },
        {
          key: 'original_name',
          header: 'Filename',
          sortable: true,
          className: 'cell-truncate',
          render: (a: PackageArtifact) => (
            <span title={a.original_name || a.id}>{a.original_name || a.id.slice(0, 12)}</span>
          ),
        },
        {
          key: 'size',
          header: 'Size',
          sortable: true,
          render: (a: PackageArtifact) => <span>{formatBytes(a.size)}</span>,
        },
        {
          key: 'created_at',
          header: 'Cached',
          sortable: true,
          render: (a: PackageArtifact) => (
            <span>{new Date(a.created_at).toLocaleDateString()}</span>
          ),
        },
        {
          key: 'actions',
          header: '',
          render: (a: PackageArtifact) => (
            <div className="action-buttons">
              <a
                href={getDownloadUrl(projectName!, packageName!, getDownloadRef(a))}
                className="btn btn-icon"
                download
                title="Download"
              >
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
                  <polyline points="7 10 12 15 17 10" />
                  <line x1="12" y1="15" x2="12" y2="3" />
                </svg>
              </a>
              <button
                className="btn btn-icon"
                onClick={(e) => handleMenuOpen(e, a.id)}
                title="More actions"
              >
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                  <circle cx="12" cy="12" r="1" />
                  <circle cx="12" cy="5" r="1" />
                  <circle cx="12" cy="19" r="1" />
                </svg>
              </button>
            </div>
          ),
        },
      ]
    : [
        // Regular project columns: Version, Filename, Size, Created
        // Valid sort fields: created_at, size, original_name
        {
          key: 'version',
          header: 'Version',
          // version is from format_metadata, not a sortable DB field
          render: (a: PackageArtifact) => (
            <strong
              className={`tag-name-link ${selectedArtifact?.id === a.id ? 'selected' : ''}`}
              onClick={() => handleArtifactSelect(a)}
              style={{ cursor: 'pointer' }}
            >
              <span className="version-badge">{getArtifactVersion(a) || a.id.slice(0, 12)}</span>
            </strong>
          ),
        },
        {
          key: 'original_name',
          header: 'Filename',
          sortable: true,
          className: 'cell-truncate',
          render: (a: PackageArtifact) => (
            <span title={a.original_name || undefined}>{a.original_name || '—'}</span>
          ),
        },
        {
          key: 'size',
          header: 'Size',
          sortable: true,
          render: (a: PackageArtifact) => <span>{formatBytes(a.size)}</span>,
        },
        {
          key: 'created_at',
          header: 'Created',
          sortable: true,
          render: (a: PackageArtifact) => (
            <span title={`by ${a.created_by}`}>{new Date(a.created_at).toLocaleDateString()}</span>
          ),
        },
        {
          key: 'actions',
          header: '',
          render: (a: PackageArtifact) => (
            <div className="action-buttons">
              <a
                href={getDownloadUrl(projectName!, packageName!, getDownloadRef(a))}
                className="btn btn-icon"
                download
                title="Download"
              >
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
                  <polyline points="7 10 12 15 17 10" />
                  <line x1="12" y1="15" x2="12" y2="3" />
                </svg>
              </a>
              <button
                className="btn btn-icon"
                onClick={(e) => handleMenuOpen(e, a.id)}
                title="More actions"
              >
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                  <circle cx="12" cy="12" r="1" />
                  <circle cx="12" cy="5" r="1" />
                  <circle cx="12" cy="19" r="1" />
                </svg>
              </button>
            </div>
          ),
        },
      ];

  // Find the artifact for the open menu
  const openMenuArtifact = artifacts.find(a => a.id === openMenuId);

  // Close menu when clicking outside
  const handleClickOutside = () => {
    if (openMenuId) {
      setOpenMenuId(null);
      setMenuPosition(null);
    }
  };

  // Render dropdown menu as a portal-like element
  const renderActionMenu = () => {
    if (!openMenuId || !menuPosition || !openMenuArtifact) return null;
    const a = openMenuArtifact;
    return (
      <div
        className="action-menu-backdrop"
        onClick={handleClickOutside}
      >
        <div
          className="action-menu-dropdown"
          style={{ top: menuPosition.top, left: menuPosition.left }}
          onClick={(e) => e.stopPropagation()}
        >
          <button onClick={() => { setViewArtifactId(a.id); setShowArtifactIdModal(true); setOpenMenuId(null); setMenuPosition(null); }}>
            View Artifact ID
          </button>
          <button onClick={() => { navigator.clipboard.writeText(a.id); setOpenMenuId(null); setMenuPosition(null); }}>
            Copy Artifact ID
          </button>
          <button onClick={() => { const version = getArtifactVersion(a); const ref = version || `artifact:${a.id}`; fetchEnsureFileForRef(ref); setOpenMenuId(null); setMenuPosition(null); }}>
            View Ensure File
          </button>
          <button onClick={() => { handleArtifactSelect(a); setShowDepsModal(true); setOpenMenuId(null); setMenuPosition(null); }}>
            View Dependencies
          </button>
        </div>
      </div>
    );
  };

  if (loading && !artifactsData) {
    return <div className="loading">Loading...</div>;
  }

  if (accessDenied) {
    return (
      <div className="home">
        <Breadcrumb
          items={[
            { label: 'Projects', href: '/' },
            { label: projectName!, href: `/project/${projectName}` },
          ]}
        />
        <div className="error-message" style={{ textAlign: 'center', padding: '48px 24px' }}>
          <h2>Access Denied</h2>
          <p>You do not have permission to view this package.</p>
          {!user && (
            <p style={{ marginTop: '16px' }}>
              <a href="/login" className="btn btn-primary">Sign in</a>
            </p>
          )}
        </div>
      </div>
    );
  }

  return (
    <div className="home">
      <Breadcrumb
        items={[
          { label: 'Projects', href: '/' },
          { label: projectName!, href: `/project/${projectName}` },
          { label: packageName! },
        ]}
      />

      <div className="page-header">
        <div className="page-header__info">
          <div className="page-header__title-row">
            <h1>{packageName}</h1>
            {pkg && <Badge variant="default">{pkg.format}</Badge>}
            {user && canWrite && !isSystemProject && (
              <button
                className="btn btn-primary btn-small header-upload-btn"
                onClick={() => setShowUploadModal(true)}
              >
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ marginRight: '6px' }}>
                  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
                  <polyline points="17 8 12 3 7 8" />
                  <line x1="12" y1="3" x2="12" y2="15" />
                </svg>
                Upload
              </button>
            )}
          </div>
          {pkg?.description && <p className="description">{pkg.description}</p>}
          <div className="page-header__meta">
            <span className="meta-item">
              in <a href={`/project/${projectName}`}>{projectName}</a>
            </span>
            {pkg && (
              <>
                <span className="meta-item">Created {new Date(pkg.created_at).toLocaleDateString()}</span>
                {pkg.updated_at !== pkg.created_at && (
                  <span className="meta-item">Updated {new Date(pkg.updated_at).toLocaleDateString()}</span>
                )}
              </>
            )}
          </div>
          {pkg && pkg.artifact_count !== undefined && (
            <div className="package-header-stats">
              {pkg.artifact_count !== undefined && (
                <span className="stat-item">
                  <strong>{pkg.artifact_count}</strong> {isSystemProject ? 'versions' : 'artifacts'}
                </span>
              )}
              {pkg.total_size !== undefined && pkg.total_size > 0 && (
                <span className="stat-item">
                  <strong>{formatBytes(pkg.total_size)}</strong> total
                </span>
              )}
            </div>
          )}
        </div>
      </div>

      {error && <div className="error-message">{error}</div>}
      {uploadSuccess && <div className="success-message">{uploadSuccess}</div>}


      <div className="section-header">
        <h2>{isSystemProject ? 'Versions' : 'Artifacts'}</h2>
      </div>

      <div className="list-controls">
        <SearchInput
          value={search}
          onChange={handleSearchChange}
          placeholder="Filter artifacts..."
          className="list-controls__search"
        />
      </div>

      {hasActiveFilters && (
        <FilterChipGroup onClearAll={clearFilters}>
          {search && <FilterChip label="Filter" value={search} onRemove={() => handleSearchChange('')} />}
        </FilterChipGroup>
      )}

      <div className="data-table--responsive">
        <DataTable
          data={artifacts}
          columns={columns}
          keyExtractor={(a) => a.id}
          emptyMessage={
            hasActiveFilters
              ? 'No artifacts match your filters. Try adjusting your search.'
              : 'No artifacts yet. Upload a file to get started!'
          }
          onSort={handleSortChange}
          sortKey={sort}
          sortOrder={order}
        />
      </div>

      {pagination && pagination.total_pages > 1 && (
        <Pagination
          page={pagination.page}
          totalPages={pagination.total_pages}
          total={pagination.total}
          limit={pagination.limit}
          onPageChange={handlePageChange}
        />
      )}

      {/* Used By (Reverse Dependencies) Section - only show if there are reverse deps or error */}
      {(reverseDeps.length > 0 || reverseDepsError) && (
        <div className="used-by-section card">
          <h3>Used By</h3>
          {reverseDepsError && (
            <div className="error-message">{reverseDepsError}</div>
          )}
          <div className="reverse-deps-list">
            <div className="deps-summary">
              {reverseDepsTotal} {reverseDepsTotal === 1 ? 'package depends' : 'packages depend'} on this:
            </div>
            <ul className="deps-items">
              {reverseDeps.map((dep) => (
                <li key={dep.artifact_id} className="dep-item reverse-dep-item">
                  <Link
                    to={`/project/${dep.project}/${dep.package}${dep.version ? `?version=${dep.version}` : ''}`}
                    className="dep-link"
                  >
                    {dep.project}/{dep.package}
                    {dep.version && (
                      <span className="dep-version">v{dep.version}</span>
                    )}
                  </Link>
                  <span className="dep-requires">
                    requires @ {dep.constraint_value}
                  </span>
                </li>
              ))}
            </ul>
            {(reverseDepsHasMore || reverseDepsPage > 1) && (
              <div className="reverse-deps-pagination">
                <button
                  className="btn btn-secondary btn-small"
                  onClick={() => fetchReverseDeps(reverseDepsPage - 1)}
                  disabled={reverseDepsPage <= 1 || reverseDepsLoading}
                >
                  Previous
                </button>
                <span className="pagination-info">Page {reverseDepsPage}</span>
                <button
                  className="btn btn-secondary btn-small"
                  onClick={() => fetchReverseDeps(reverseDepsPage + 1)}
                  disabled={!reverseDepsHasMore || reverseDepsLoading}
                >
                  Next
                </button>
              </div>
            )}
          </div>
        </div>
      )}

      {/* Dependency Graph Modal */}
      {showGraph && selectedArtifact && (
        <DependencyGraph
          projectName={projectName!}
          packageName={packageName!}
          tagName={getArtifactVersion(selectedArtifact) || `artifact:${selectedArtifact.id}`}
          onClose={() => setShowGraph(false)}
        />
      )}

      {/* Upload Modal */}
      {showUploadModal && (
        <div className="modal-overlay" onClick={() => setShowUploadModal(false)}>
          <div className="upload-modal" onClick={(e) => e.stopPropagation()}>
            <div className="modal-header">
              <h3>Upload Artifact</h3>
              <button
                className="modal-close"
                onClick={() => setShowUploadModal(false)}
                title="Close"
              >
                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                  <line x1="18" y1="6" x2="6" y2="18"></line>
                  <line x1="6" y1="6" x2="18" y2="18"></line>
                </svg>
              </button>
            </div>
            <div className="modal-body">
              <DragDropUpload
                projectName={projectName!}
                packageName={packageName!}
                onUploadComplete={(result) => {
                  handleUploadComplete(result);
                  setShowUploadModal(false);
                }}
                onUploadError={handleUploadError}
              />
            </div>
          </div>
        </div>
      )}

      {/* Ensure File Modal */}
      {showEnsureFile && (
        <div className="modal-overlay" onClick={() => setShowEnsureFile(false)}>
          <div className="ensure-file-modal" onClick={(e) => e.stopPropagation()}>
            <div className="ensure-file-header">
              <h3>orchard.ensure for {ensureFileTagName}</h3>
              <div className="ensure-file-actions">
                {ensureFileContent && (
                  <CopyButton text={ensureFileContent} />
                )}
                <button
                  className="modal-close"
                  onClick={() => setShowEnsureFile(false)}
                  title="Close"
                >
                  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                    <line x1="18" y1="6" x2="6" y2="18"></line>
                    <line x1="6" y1="6" x2="18" y2="18"></line>
                  </svg>
                </button>
              </div>
            </div>
            <div className="ensure-file-content">
              {ensureFileLoading ? (
                <div className="ensure-file-loading">Loading...</div>
              ) : ensureFileError ? (
                <div className="ensure-file-error">{ensureFileError}</div>
              ) : ensureFileContent ? (
                <pre className="ensure-file-yaml"><code>{ensureFileContent}</code></pre>
              ) : (
                <div className="ensure-file-empty">No dependencies defined for this artifact.</div>
              )}
            </div>
            <div className="ensure-file-footer">
              <p className="ensure-file-hint">
                Save this as <code>orchard.ensure</code> in your project root to declare dependencies.
              </p>
            </div>
          </div>
        </div>
      )}

      {/* Dependencies Modal */}
      {showDepsModal && selectedArtifact && (
        <div className="modal-overlay" onClick={() => setShowDepsModal(false)}>
          <div className="deps-modal" onClick={(e) => e.stopPropagation()}>
            <div className="modal-header">
              <h3>Dependencies for {selectedArtifact.original_name || selectedArtifact.id.slice(0, 12)}</h3>
              <button
                className="modal-close"
                onClick={() => setShowDepsModal(false)}
                title="Close"
              >
                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                  <line x1="18" y1="6" x2="6" y2="18"></line>
                  <line x1="6" y1="6" x2="18" y2="18"></line>
                </svg>
              </button>
            </div>
            <div className="modal-body">
              <div className="deps-modal-controls">
                <button
                  className="btn btn-secondary btn-small"
                  onClick={fetchEnsureFile}
                  disabled={ensureFileLoading}
                >
                  View Ensure File
                </button>
                <button
                  className="btn btn-secondary btn-small"
                  onClick={() => { setShowDepsModal(false); setShowGraph(true); }}
                >
                  View Graph
                </button>
              </div>
              {depsLoading ? (
                <div className="deps-loading">Loading dependencies...</div>
              ) : depsError ? (
                <div className="deps-error">{depsError}</div>
              ) : dependencies.length === 0 ? (
                <div className="deps-empty">No dependencies</div>
              ) : (
                <div className="deps-list">
                  <div className="deps-summary">
                    {dependencies.length} {dependencies.length === 1 ? 'dependency' : 'dependencies'}:
                  </div>
                  <ul className="deps-items">
                    {dependencies.map((dep) => (
                      <li key={dep.id} className="dep-item">
                        <Link
                          to={`/project/${dep.project}/${dep.package}`}
                          className="dep-link"
                          onClick={() => setShowDepsModal(false)}
                        >
                          {dep.project}/{dep.package}
                        </Link>
                        <span className="dep-constraint">
                          @ {dep.version}
                        </span>
                        <span className="dep-status dep-status--ok" title="Package exists">
                          &#10003;
                        </span>
                      </li>
                    ))}
                  </ul>
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* Artifact ID Modal */}
      {showArtifactIdModal && viewArtifactId && (
        <div className="modal-overlay" onClick={() => setShowArtifactIdModal(false)}>
          <div className="artifact-id-modal" onClick={(e) => e.stopPropagation()}>
            <div className="modal-header">
              <h3>Artifact ID</h3>
              <button
                className="modal-close"
                onClick={() => setShowArtifactIdModal(false)}
                title="Close"
              >
                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                  <line x1="18" y1="6" x2="6" y2="18"></line>
                  <line x1="6" y1="6" x2="18" y2="18"></line>
                </svg>
              </button>
            </div>
            <div className="modal-body">
              <p className="modal-description">SHA256 hash identifying this artifact:</p>
              <div className="artifact-id-display">
                <code>{viewArtifactId}</code>
                <CopyButton text={viewArtifactId} />
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Action Menu Dropdown */}
      {renderActionMenu()}
    </div>
  );
}

export default PackagePage;
