import { useState, type ReactElement } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { MissionTimeline } from '@/components/projects/mission-timeline';
import { PrdViewer } from '@/components/projects/prd-viewer';
import { TaskDetailModal } from '@/components/tasks/task-detail-modal';
import { TaskListView } from '@/components/tasks/task-list-view';
import { TaskStatusSummary } from '@/components/tasks/task-status-summary';
import {
  PartialDataNotice,
  StaleDataNotice,
  UnavailableDataNotice,
} from '@/components/freshness/freshness-notices';
import { api } from '@/lib/api';
import { cn } from '@/lib/cn';
import type { Mission, Project, Task, TaskStatus } from '@/lib/types';
import {
  combineFreshness,
  UNKNOWN_VERDICT,
  verdictValue,
  type FreshSnapshot,
} from '@/lib/freshness/model';
import { describeFailure, useFreshCollection } from '@/lib/freshness/use-fresh-collection';
import {
  validateMissionCollection,
  validateProjectEntity,
  validateTaskCollection,
} from '@/lib/freshness/validators';

type Tab = 'overview' | 'tasks' | 'missions' | 'prd';

const projectStatusColors: Record<string, string> = {
  active: 'bg-success/20 text-success',
  paused: 'bg-warning/20 text-warning',
  completed: 'bg-blue-600/20 text-blue-400',
  archived: 'bg-gray-600/20 text-gray-400',
};

const taskStatusColors: Record<string, string> = {
  'not-started': 'bg-gray-600/20 text-gray-300',
  'in-progress': 'bg-blue-600/20 text-blue-400',
  blocked: 'bg-error/20 text-error',
  done: 'bg-success/20 text-success',
  cancelled: 'bg-gray-600/20 text-gray-500',
};

interface TabButtonProps {
  id: Tab;
  label: string;
  activeTab: Tab;
  onClick: (tab: Tab) => void;
}

function TabButton({ id, label, activeTab, onClick }: TabButtonProps): ReactElement {
  return (
    <button
      type="button"
      onClick={() => onClick(id)}
      className={cn(
        'border-b-2 px-4 py-2 text-sm transition-colors',
        activeTab === id
          ? 'border-text-primary text-text-primary'
          : 'border-transparent text-text-muted hover:text-text-secondary',
      )}
    >
      {label}
    </button>
  );
}

/** Remounts per project id so no state from one project renders for another. */
export function ProjectDetailPage(): ReactElement {
  const { id = '' } = useParams();
  return <ProjectDetail id={id} key={id} />;
}

function ProjectDetail({ id }: { id: string }): ReactElement {
  const navigate = useNavigate();
  const enabled = id.length > 0;

  // Primary collection gates the surface; missions and tasks are secondaries
  // whose failures degrade the surface to `partial` instead of rendering
  // empty healthy lists.
  const project = useFreshCollection<Project>({
    source: `gateway:/api/projects/${id}`,
    fetcher: (signal) => api<unknown>(`/api/projects/${id}`, { signal }),
    validate: validateProjectEntity,
    // No last-known restore: the entity carries workspace identity that
    // cannot be scope-checked before display (see ProjectsPage note).
    enabled,
  });
  const missions = useFreshCollection<Mission[]>({
    source: 'gateway:/api/missions',
    fetcher: (signal) => api<unknown>('/api/missions', { signal }),
    validate: validateMissionCollection,
    cacheKey: enabled ? 'missions' : null,
    enabled,
  });
  const tasks = useFreshCollection<Task[]>({
    source: `gateway:/api/tasks?projectId=${id}`,
    fetcher: (signal) => api<unknown>(`/api/tasks?projectId=${id}`, { signal }),
    validate: validateTaskCollection,
    cacheKey: enabled ? `project-tasks:${id}` : null,
    enabled,
  });

  const [activeTab, setActiveTab] = useState<Tab>('overview');
  const [taskFilter, setTaskFilter] = useState<TaskStatus | 'all'>('all');
  const [selectedTask, setSelectedTask] = useState<Task | null>(null);

  const surface = combineFreshness(project.freshness, [missions.freshness, tasks.freshness]);
  const tasksVerified = tasks.freshness === 'current';
  const projectMissions = missions.data?.filter((mission) => mission.projectId === id) ?? null;

  const retryAll = (): void => {
    void Promise.all([project.revalidate(), missions.revalidate(), tasks.revalidate()]);
  };

  if (!enabled) {
    return (
      <div className="flex min-h-screen flex-col px-4 py-6 sm:px-6">
        <header className="mb-6 border-b px-1 pb-3">
          <h1 className="text-2xl font-semibold">Project</h1>
        </header>
        <div role="alert" className="rounded-lg border border-error/40 px-4 py-3 text-sm">
          Project id is missing.
        </div>
        <button
          type="button"
          onClick={() => navigate('/projects')}
          className="mt-4 w-fit text-sm underline"
        >
          Back to projects
        </button>
      </div>
    );
  }

  if (project.freshness === 'unknown') {
    return (
      <div className="flex min-h-screen flex-col px-4 py-6 sm:px-6">
        <header className="mb-6 border-b px-1 pb-3">
          <h1 className="text-2xl font-semibold">Project</h1>
        </header>
        <p className="py-16 text-center text-sm text-text-muted">Loading project...</p>
      </div>
    );
  }

  if (project.freshness === 'unavailable' || project.data === null) {
    return (
      <div className="flex min-h-screen flex-col px-4 py-6 sm:px-6">
        <header className="mb-6 border-b px-1 pb-3">
          <h1 className="text-2xl font-semibold">Project</h1>
        </header>
        <UnavailableDataNotice
          title="This project"
          detail={describeFailure(project.failure)}
          onRetry={retryAll}
        />
        <button
          type="button"
          onClick={() => navigate('/projects')}
          className="mt-4 w-fit text-sm underline"
        >
          Back to projects
        </button>
      </div>
    );
  }

  const projectTasks = tasks.data ?? null;
  const filteredTasks =
    projectTasks === null
      ? []
      : taskFilter === 'all'
        ? projectTasks
        : projectTasks.filter((task) => task.status === taskFilter);

  // Derived completion verdicts: unknown (never green) unless the task
  // collection is verified current.
  const doneCount = projectTasks?.filter((task) => task.status === 'done').length ?? 0;
  const inProgressCount = projectTasks?.filter((task) => task.status === 'in-progress').length ?? 0;
  const blockedCount = projectTasks?.filter((task) => task.status === 'blocked').length ?? 0;

  const prdContent = getPrdContent(project.data);
  const tabs: Array<{ id: Tab; label: string }> = [
    { id: 'overview', label: 'Overview' },
    {
      id: 'tasks',
      label: `Tasks (${projectTasks === null ? UNKNOWN_VERDICT : projectTasks.length})`,
    },
    {
      id: 'missions',
      label: `Missions (${projectMissions === null ? UNKNOWN_VERDICT : projectMissions.length})`,
    },
    ...(prdContent ? [{ id: 'prd' as const, label: 'PRD' }] : []),
  ];

  const staleSnapshot: FreshSnapshot<unknown> | null =
    project.freshness === 'stale'
      ? project.snapshot
      : missions.freshness === 'stale'
        ? missions.snapshot
        : tasks.freshness === 'stale'
          ? tasks.snapshot
          : null;
  const missingSections: string[] = [];
  if (missions.freshness === 'unavailable') missingSections.push('Missions');
  if (tasks.freshness === 'unavailable') missingSections.push('Tasks');

  return (
    <div data-freshness={surface} className="flex min-h-screen flex-col px-4 py-6 sm:px-6">
      <header className="mb-6 border-b px-1 pb-3">
        <nav className="mb-4 flex items-center gap-2 text-sm text-text-muted">
          <button
            type="button"
            onClick={() => navigate('/projects')}
            className="hover:text-text-secondary"
          >
            Projects
          </button>
          <span>/</span>
          <span className="text-text-primary">{project.data.name}</span>
        </nav>

        <div className="flex items-start justify-between gap-4">
          <div>
            <div className="flex items-center gap-3">
              <h1 className="text-2xl font-semibold text-text-primary">{project.data.name}</h1>
              <span
                className={cn(
                  'rounded-full px-2 py-0.5 text-xs',
                  projectStatusColors[project.data.status] ?? 'bg-gray-600/20 text-gray-400',
                )}
              >
                {project.data.status}
              </span>
            </div>
            {project.data.description ? (
              <p className="mt-1 text-sm text-text-muted">{project.data.description}</p>
            ) : null}
            <p className="mt-2 text-xs text-text-muted">
              Created {new Date(project.data.createdAt).toLocaleDateString()} · Updated{' '}
              {new Date(project.data.updatedAt).toLocaleDateString()}
            </p>
          </div>
        </div>
      </header>

      {staleSnapshot !== null ? (
        <div className="mb-6">
          <StaleDataNotice label={staleSnapshot} onRetry={retryAll} />
        </div>
      ) : null}

      {missingSections.length > 0 ? (
        <div className="mb-6">
          <PartialDataNotice missing={missingSections} onRetry={retryAll} />
        </div>
      ) : null}

      <div className="mb-6 grid grid-cols-2 gap-3 sm:grid-cols-4">
        <StatCard
          label="Tasks"
          value={projectTasks === null ? UNKNOWN_VERDICT : String(projectTasks.length)}
        />
        <StatCard
          label="Done"
          value={verdictValue(tasksVerified, String(doneCount))}
          valueClass={tasksVerified ? 'text-success' : undefined}
        />
        <StatCard
          label="In Progress"
          value={verdictValue(tasksVerified, String(inProgressCount))}
          valueClass={tasksVerified ? 'text-blue-400' : undefined}
        />
        <StatCard
          label="Blocked"
          value={verdictValue(tasksVerified, String(blockedCount))}
          valueClass={tasksVerified && blockedCount > 0 ? 'text-error' : undefined}
        />
      </div>

      <div className="mb-6 flex gap-0 border-b border-surface-border">
        {tabs.map((tab) => (
          <TabButton
            key={tab.id}
            id={tab.id}
            label={tab.label}
            activeTab={activeTab}
            onClick={setActiveTab}
          />
        ))}
      </div>

      {activeTab === 'overview' ? (
        <OverviewTab project={project.data} missions={projectMissions} tasks={projectTasks} />
      ) : null}

      {activeTab === 'tasks' ? (
        <div>
          {projectTasks === null ? (
            <UnavailableDataNotice
              title="Tasks"
              detail={describeFailure(tasks.failure)}
              onRetry={retryAll}
            />
          ) : (
            <>
              <div className="mb-4">
                <TaskStatusSummary
                  tasks={projectTasks}
                  activeFilter={taskFilter}
                  onFilterChange={setTaskFilter}
                />
              </div>
              <TaskListView tasks={filteredTasks} onTaskClick={setSelectedTask} />
            </>
          )}
        </div>
      ) : null}

      {activeTab === 'missions' ? (
        projectMissions === null ? (
          <UnavailableDataNotice
            title="Missions"
            detail={describeFailure(missions.failure)}
            onRetry={retryAll}
          />
        ) : (
          <MissionTimeline missions={projectMissions} />
        )
      ) : null}

      {activeTab === 'prd' && prdContent ? (
        <div className="rounded-lg border border-surface-border bg-surface-card p-6">
          <PrdViewer content={prdContent} />
        </div>
      ) : null}

      {selectedTask ? (
        <TaskDetailModal task={selectedTask} onClose={() => setSelectedTask(null)} />
      ) : null}
    </div>
  );
}

function OverviewTab({
  project,
  missions,
  tasks,
}: {
  project: Project;
  missions: Mission[] | null;
  tasks: Task[] | null;
}): ReactElement {
  const recentTasks =
    tasks === null
      ? null
      : [...tasks]
          .sort(
            (left, right) =>
              new Date(right.updatedAt).getTime() - new Date(left.updatedAt).getTime(),
          )
          .slice(0, 5);

  return (
    <div className="grid gap-6 lg:grid-cols-2">
      <section>
        <h2 className="mb-3 text-sm font-semibold text-text-secondary">Recent Tasks</h2>
        {recentTasks === null ? (
          <UnavailableDataNotice title="Tasks" />
        ) : recentTasks.length === 0 ? (
          <div className="rounded-lg border border-surface-border bg-surface-card p-4 text-center">
            <p className="text-sm text-text-muted">No tasks yet</p>
          </div>
        ) : (
          <div className="space-y-2">
            {recentTasks.map((task) => (
              <div
                key={task.id}
                className="flex items-center justify-between gap-2 rounded-lg border border-surface-border bg-surface-card px-3 py-2"
              >
                <span className="truncate text-sm text-text-primary">{task.title}</span>
                <span
                  className={cn(
                    'shrink-0 rounded-full px-2 py-0.5 text-xs',
                    taskStatusColors[task.status] ?? 'bg-gray-600/20 text-gray-400',
                  )}
                >
                  {task.status}
                </span>
              </div>
            ))}
          </div>
        )}
      </section>

      <section>
        <h2 className="mb-3 text-sm font-semibold text-text-secondary">Missions</h2>
        {missions === null ? (
          <UnavailableDataNotice title="Missions" />
        ) : missions.length === 0 ? (
          <div className="rounded-lg border border-surface-border bg-surface-card p-4 text-center">
            <p className="text-sm text-text-muted">No missions yet</p>
          </div>
        ) : (
          <MissionTimeline missions={missions.slice(0, 4)} />
        )}
      </section>

      {project.metadata && Object.keys(project.metadata).length > 0 ? (
        <section className="lg:col-span-2">
          <h2 className="mb-3 text-sm font-semibold text-text-secondary">Project Metadata</h2>
          <div className="rounded-lg border border-surface-border bg-surface-card p-4">
            <pre className="overflow-x-auto text-xs text-text-muted">
              {JSON.stringify(project.metadata, null, 2)}
            </pre>
          </div>
        </section>
      ) : null}
    </div>
  );
}

function StatCard({
  label,
  value,
  valueClass,
}: {
  label: string;
  value: string;
  valueClass?: string;
}): ReactElement {
  return (
    <div className="rounded-lg border border-surface-border bg-surface-card p-3">
      <p className="text-xs text-text-muted">{label}</p>
      <p className={cn('mt-1 text-lg font-semibold', valueClass ?? 'text-text-primary')}>{value}</p>
    </div>
  );
}

function getPrdContent(project: Project): string | null {
  if (!project.metadata) return null;

  const prd = project.metadata['prd'];
  if (typeof prd === 'string' && prd.trim().length > 0) {
    return prd;
  }

  const prdContent = project.metadata['prdContent'];
  if (typeof prdContent === 'string' && prdContent.trim().length > 0) {
    return prdContent;
  }

  return null;
}
