import { useQuery } from '@tanstack/react-query';
import { Link } from 'react-router-dom';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';

import { fetchProjects, fetchLanguages, type ProjectSummary, type Source } from '../api/client';
import { ContributionGraph, AllTimeGraph } from '../components/ContributionGraph';

export function DashPage() {
  const projectsQ = useQuery({
    queryKey: ['projects'],
    queryFn: fetchProjects,
    refetchInterval: 60_000,
  });

  const projects = projectsQ.data ?? [];
  const ranked = rankProjects(projects);

  return (
    <>
      <Row className="mb-3">
        <Col>
          <p>
            i rarely say anything that warrants capital letters. a peek into the
            projects i'm working on is below.
          </p>
        </Col>
      </Row>
      <ContributionGraph />
      <AllTimeGraph />
      {projectsQ.isLoading && <p>loading...</p>}
      {projectsQ.isError && (
        <p>error: {(projectsQ.error as Error).message}</p>
      )}
      <Row xs={1} md={2} lg={3} className="g-3">
        {ranked.map((p) => (
          <Col key={`${p.source}:${p.repo}`}>
            <ProjectCard project={p} />
          </Col>
        ))}
      </Row>
    </>
  );
}

function ProjectCard({ project: p }: { project: ProjectSummary }) {
  const langsQ = useQuery({
    queryKey: ['languages', p.source, p.host, p.repo],
    queryFn: () => fetchLanguages(p.source as Source, p.host, p.repo),
    enabled: p.source === 'github' || p.source === 'gitea',
    staleTime: 10 * 60_000,
  });

  const langs = langsQ.data;
  const topLangs = langs ? topLanguages(langs, 3) : null;

  return (
    <Link to={`/project/${p.source}/${p.repo}`} className="text-decoration-none">
      <div className="project-card p-3">
        <h5 className="mb-1">{p.repo}</h5>
        <small className="text-muted d-block mb-2">
          {p.source}
          {topLangs && ` · ${topLangs}`}
        </small>
        <div className="d-flex gap-3" style={{ fontSize: '0.8rem' }}>
          {p.commit_count > 0 && <span>{p.commit_count} commits</span>}
          {p.issue_count > 0 && <span>{p.issue_count} issues</span>}
          {p.pr_count > 0 && <span>{p.pr_count} prs</span>}
        </div>
        <div style={{ fontSize: '0.75rem', opacity: 0.6, marginTop: '0.25rem' }}>
          {formatRange(p.first_activity, p.last_activity)}
        </div>
      </div>
    </Link>
  );
}

function topLanguages(langs: Record<string, number>, n: number): string {
  return Object.entries(langs)
    .sort(([, a], [, b]) => b - a)
    .slice(0, n)
    .map(([lang]) => lang.toLowerCase())
    .join(', ');
}

function formatRange(first: string | null, last: string | null): string {
  const fmt = (iso: string) =>
    new Date(iso).toLocaleDateString('en-GB', { month: 'short', year: 'numeric' }).toLowerCase();
  if (first && last) return `${fmt(first)} — ${fmt(last)}`;
  if (last) return fmt(last);
  return '';
}

function rankProjects(projects: ProjectSummary[]): ProjectSummary[] {
  if (projects.length === 0) return [];
  const now = Date.now();
  const maxVolume = Math.max(...projects.map((p) => p.commit_count + p.issue_count + p.pr_count));
  const oldest = Math.min(
    ...projects.map((p) => (p.last_activity ? new Date(p.last_activity).getTime() : 0)),
  );
  const range = now - oldest || 1;

  return [...projects].sort((a, b) => score(b) - score(a));

  function score(p: ProjectSummary): number {
    const volume = (p.commit_count + p.issue_count + p.pr_count) / (maxVolume || 1);
    const recency = p.last_activity
      ? (new Date(p.last_activity).getTime() - oldest) / range
      : 0;
    return 0.6 * recency + 0.4 * volume;
  }
}
