'use client'

import * as React from 'react'
import {
  AlertCircle,
  AlertTriangle,
  CheckCircle2,
  ChevronDown,
  ChevronRight,
  Clock,
  Inbox,
  TerminalSquare,
} from 'lucide-react'
import { cn } from '../../lib/utils'
import { SessionCard, SessionCardSkeleton, formatRelative } from './SessionCard'
import { resolveSessionStatus } from './status'
import type { SessionStatusKind, SessionSummary } from './types'

export interface SessionListProps {
  sessions: SessionSummary[]
  isLoading?: boolean
  error?: string | null
  /** Grid of cards (default) or a compact table of rows. */
  layout?: 'grid' | 'table'
  /** In `table` layout, group rows under collapsible project headers. */
  groupByProject?: boolean
  /** Slot rendered above the list (filters/search — the app owns them). */
  renderFilters?: React.ReactNode
  /** Inject routing for a card/row (grid: card title/Details become links). */
  href?: (id: string) => string
  onSessionClick?: (session: SessionSummary) => void
  onOpenTerminal?: (id: string) => void
  /** Message shown when there are no sessions. */
  emptyLabel?: string
  /** Number of skeletons while loading. Default 6. */
  skeletonCount?: number
  className?: string
}

const STATUS_ICON: Record<SessionStatusKind, React.ComponentType<{ className?: string }>> = {
  active: TerminalSquare,
  success: CheckCircle2,
  completed: CheckCircle2,
  error: AlertCircle,
  warning: AlertTriangle,
  idle: Clock,
}

interface ProjectGroup {
  project: string
  sessions: SessionSummary[]
}

/** Group + sort sessions by project name for the grouped table layout. */
function groupByProjectName(sessions: SessionSummary[]): ProjectGroup[] {
  const groups = new Map<string, ProjectGroup>()
  for (const session of sessions) {
    const key = session.projectName ?? 'Ungrouped'
    if (!groups.has(key)) groups.set(key, { project: key, sessions: [] })
    groups.get(key)!.sessions.push(session)
  }
  return Array.from(groups.values())
}

function SessionRow({
  session,
  onSessionClick,
  onOpenTerminal,
}: {
  session: SessionSummary
  onSessionClick?: (s: SessionSummary) => void
  onOpenTerminal?: (id: string) => void
}) {
  const status = resolveSessionStatus(session)
  const Icon = STATUS_ICON[status.kind]
  return (
    <button
      type="button"
      data-testid="session-row"
      onClick={() => onSessionClick?.(session)}
      className="group flex w-full items-center gap-4 border-b border-border p-4 text-left transition-colors last:border-b-0 hover:bg-accent"
    >
      <Icon className={cn('h-4 w-4 flex-shrink-0', status.toneClassName)} />
      <div className="min-w-0 flex-1">
        <div className="flex items-baseline gap-2">
          <span className="truncate font-medium text-foreground group-hover:text-primary">{session.name}</span>
          {session.number != null && <span className="text-xs text-muted-foreground">#{session.number}</span>}
        </div>
        <div className="mt-1 flex flex-wrap items-center gap-3 text-xs text-muted-foreground">
          <span className={status.toneClassName}>{status.label}</span>
          {session.branch && (
            <span className="flex items-center gap-1">
              <span className="h-1 w-1 rounded-full bg-current" />
              <span className="font-mono">{session.branch}</span>
            </span>
          )}
          <span className="flex items-center gap-1">
            <Clock className="h-3 w-3" aria-hidden="true" />
            {formatRelative(session.updatedAt ?? session.createdAt)}
          </span>
        </div>
      </div>
      {onOpenTerminal && (
        <span
          role="button"
          tabIndex={-1}
          onClick={(e) => {
            e.stopPropagation()
            onOpenTerminal(session.id)
          }}
          className="flex-shrink-0 rounded-md p-2 text-muted-foreground opacity-0 transition-opacity hover:text-foreground group-hover:opacity-100"
          title="Open terminal"
        >
          <TerminalSquare className="h-4 w-4" aria-hidden="true" />
        </span>
      )}
    </button>
  )
}

function EmptyState({ label }: { label: string }) {
  return (
    <div
      data-testid="session-list-empty"
      className="flex flex-col items-center justify-center rounded-xl border border-border bg-card px-4 py-16 text-center"
    >
      <div className="mb-6 flex h-16 w-16 items-center justify-center rounded-full border border-border bg-muted">
        <Inbox className="h-8 w-8 text-muted-foreground" aria-hidden="true" />
      </div>
      <h3 className="text-lg font-semibold text-foreground">{label}</h3>
    </div>
  )
}

/**
 * A PURELY presentational list of sessions. It does NO data fetching and issues NO
 * per-row queries — status is injected on each `SessionSummary`. Renders a card
 * grid (`layout="grid"`) or a compact table (`layout="table"`, optionally grouped
 * by project). The app owns filters (pass them via `renderFilters`).
 */
export function SessionList({
  sessions,
  isLoading = false,
  error = null,
  layout = 'grid',
  groupByProject = false,
  renderFilters,
  href,
  onSessionClick,
  onOpenTerminal,
  emptyLabel = 'No sessions yet',
  skeletonCount = 6,
  className,
}: SessionListProps) {
  const [collapsed, setCollapsed] = React.useState<Set<string>>(new Set())
  const groups = React.useMemo(
    () => (layout === 'table' && groupByProject ? groupByProjectName(sessions) : []),
    [layout, groupByProject, sessions],
  )

  const toggle = (project: string) =>
    setCollapsed((prev) => {
      const next = new Set(prev)
      if (next.has(project)) next.delete(project)
      else next.add(project)
      return next
    })

  let body: React.ReactNode

  if (isLoading) {
    body = (
      <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
        {Array.from({ length: skeletonCount }).map((_, i) => (
          <SessionCardSkeleton key={i} />
        ))}
      </div>
    )
  } else if (error) {
    body = (
      <div
        data-testid="session-list-error"
        className="rounded-xl border border-red-500/30 bg-card px-4 py-16 text-center"
      >
        <h3 className="mb-2 text-lg font-semibold text-foreground">Failed to load sessions</h3>
        <p className="text-sm text-muted-foreground">{error}</p>
      </div>
    )
  } else if (sessions.length === 0) {
    body = <EmptyState label={emptyLabel} />
  } else if (layout === 'table') {
    if (groupByProject) {
      body = (
        <div className="space-y-2">
          {groups.map((group) => {
            const isCollapsed = collapsed.has(group.project)
            const activeCount = group.sessions.filter((s) => s.isActive).length
            return (
              <div key={group.project} className="overflow-hidden rounded-lg border border-border">
                <button
                  type="button"
                  onClick={() => toggle(group.project)}
                  className="flex w-full items-center gap-3 p-4 text-left transition-colors hover:bg-accent"
                >
                  {isCollapsed ? (
                    <ChevronRight className="h-4 w-4 flex-shrink-0 text-muted-foreground" aria-hidden="true" />
                  ) : (
                    <ChevronDown className="h-4 w-4 flex-shrink-0 text-muted-foreground" aria-hidden="true" />
                  )}
                  <div className="min-w-0 flex-1">
                    <h3 className="truncate font-medium text-foreground">{group.project}</h3>
                    <p className="mt-0.5 text-xs text-muted-foreground">
                      {group.sessions.length} session{group.sessions.length !== 1 ? 's' : ''}
                      {activeCount > 0 && <span className="ml-2 text-primary">{activeCount} active</span>}
                    </p>
                  </div>
                </button>
                {!isCollapsed && (
                  <div className="border-t border-border">
                    {group.sessions.map((session) => (
                      <SessionRow
                        key={session.id}
                        session={session}
                        onSessionClick={onSessionClick}
                        onOpenTerminal={onOpenTerminal}
                      />
                    ))}
                  </div>
                )}
              </div>
            )
          })}
        </div>
      )
    } else {
      body = (
        <div className="overflow-hidden rounded-lg border border-border">
          {sessions.map((session) => (
            <SessionRow
              key={session.id}
              session={session}
              onSessionClick={onSessionClick}
              onOpenTerminal={onOpenTerminal}
            />
          ))}
        </div>
      )
    }
  } else {
    body = (
      <div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
        {sessions.map((session) => (
          <SessionCard
            key={session.id}
            session={session}
            href={href}
            onOpen={onSessionClick ? () => onSessionClick(session) : undefined}
            onOpenTerminal={onOpenTerminal}
          />
        ))}
      </div>
    )
  }

  return (
    <div className={cn('space-y-6', className)}>
      {renderFilters}
      {body}
    </div>
  )
}
