import { Link } from "@tanstack/react-router"
import {
  ArrowCounterClockwiseIcon,
  CaretLeftIcon,
  CaretRightIcon,
  CheckCircleIcon,
} from "@phosphor-icons/react"
import { useState } from "react"

import type { AgentSource, AgentStatus, AgentThread } from "@/lib/agents/types"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { useResolveAgentThread, useThreadsPage } from "@/lib/agents/queries"
import { cn } from "@/lib/utils"

const PAGE_SIZE = 25

export interface ThreadsPageFilters {
  resolved?: boolean
  viewed?: boolean
  source?: AgentSource
  status?: AgentStatus
  q?: string
  page: number
}

type TriState = "any" | "true" | "false"

const TRI_OPTIONS: Array<{ value: TriState; label: string }> = [
  { value: "any", label: "Any" },
  { value: "true", label: "Yes" },
  { value: "false", label: "No" },
]

const SOURCE_OPTIONS: Array<{ value: AgentSource | "any"; label: string }> = [
  { value: "any", label: "Any source" },
  { value: "dashboard", label: "Dashboard" },
  { value: "github", label: "GitHub" },
  { value: "slack", label: "Slack" },
  { value: "linear", label: "Linear" },
  { value: "schedule", label: "Schedule" },
]

const STATUS_OPTIONS: Array<{ value: AgentStatus | "any"; label: string }> = [
  { value: "any", label: "Any status" },
  { value: "running", label: "Running" },
  { value: "finished", label: "Finished" },
  { value: "error", label: "Error" },
  { value: "idle", label: "Idle" },
]

function boolToTri(value?: boolean): TriState {
  if (value === true) return "true"
  if (value === false) return "false"
  return "any"
}

function triToBool(value: TriState): boolean | undefined {
  if (value === "true") return true
  if (value === "false") return false
  return undefined
}

export function AgentsThreadsPage({
  filters,
  onFiltersChange,
}: {
  filters: ThreadsPageFilters
  onFiltersChange: (next: ThreadsPageFilters) => void
}) {
  const [search, setSearch] = useState(filters.q ?? "")
  const offset = (filters.page - 1) * PAGE_SIZE
  const query = useThreadsPage({
    limit: PAGE_SIZE,
    offset,
    resolved: filters.resolved,
    viewed: filters.viewed,
    source: filters.source,
    status: filters.status,
    q: filters.q,
  })

  const data = query.data
  const items = data?.items ?? []
  const hasMore = data?.hasMore ?? false
  const exactTotal = data?.total
  const end = offset + items.length

  const update = (patch: Partial<ThreadsPageFilters>) => {
    onFiltersChange({ ...filters, ...patch, page: patch.page ?? 1 })
  }

  const onSearchSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    update({ q: search.trim() || undefined })
  }

  return (
    <main className="flex min-w-0 flex-1 flex-col overflow-y-auto px-6 py-8">
      <div className="mx-auto flex w-full max-w-3xl flex-1 flex-col gap-6">
        <div>
          <h1 className="font-heading text-base font-medium text-[var(--ui-text)]">
            Threads
          </h1>
          <p className="text-xs text-[var(--ui-text-muted)]">
            Search and filter every thread, including resolved ones.
          </p>
        </div>

        <div className="flex flex-col gap-3 rounded-lg border border-[var(--ui-border)] bg-[var(--ui-panel)] p-3">
          <form onSubmit={onSearchSubmit} className="flex gap-2">
            <Input
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder="Search by title..."
              className="h-8"
            />
            <Button type="submit" size="sm" variant="outline">
              Search
            </Button>
          </form>

          <div className="flex flex-wrap items-center gap-x-4 gap-y-2 text-xs">
            <TriFilter
              label="Resolved"
              value={boolToTri(filters.resolved)}
              onChange={(value) => update({ resolved: triToBool(value) })}
            />
            <TriFilter
              label="Viewed"
              value={boolToTri(filters.viewed)}
              onChange={(value) => update({ viewed: triToBool(value) })}
            />
            <SelectFilter
              value={filters.source ?? "any"}
              options={SOURCE_OPTIONS}
              onChange={(value) =>
                update({
                  source: value === "any" ? undefined : (value as AgentSource),
                })
              }
            />
            <SelectFilter
              value={filters.status ?? "any"}
              options={STATUS_OPTIONS}
              onChange={(value) =>
                update({
                  status: value === "any" ? undefined : (value as AgentStatus),
                })
              }
            />
          </div>
        </div>

        <div className="flex flex-col gap-1">
          {query.isLoading ? (
            <p className="px-2 py-8 text-center text-xs text-[var(--ui-text-muted)]">
              Loading...
            </p>
          ) : items.length === 0 ? (
            <p className="px-2 py-8 text-center text-xs text-[var(--ui-text-muted)]">
              No threads match these filters.
            </p>
          ) : (
            items.map((thread) => (
              <ThreadListItem key={thread.id} thread={thread} />
            ))
          )}
        </div>

        {(items.length > 0 || filters.page > 1) && (
          <div className="mt-auto flex items-center justify-between pt-2 text-xs text-[var(--ui-text-muted)]">
            <span>
              {items.length > 0 ? `${offset + 1}–${end}` : "No results"}
              {exactTotal != null ? ` of ${exactTotal}` : hasMore ? "+" : ""}
            </span>
            <div className="flex items-center gap-2">
              <Button
                size="sm"
                variant="outline"
                disabled={filters.page <= 1}
                onClick={() => update({ page: filters.page - 1 })}
              >
                <CaretLeftIcon className="size-3" />
                Prev
              </Button>
              <span>Page {filters.page}</span>
              <Button
                size="sm"
                variant="outline"
                disabled={!hasMore}
                onClick={() => update({ page: filters.page + 1 })}
              >
                Next
                <CaretRightIcon className="size-3" />
              </Button>
            </div>
          </div>
        )}
      </div>
    </main>
  )
}

function TriFilter({
  label,
  value,
  onChange,
}: {
  label: string
  value: TriState
  onChange: (value: TriState) => void
}) {
  return (
    <div className="flex items-center gap-1.5">
      <span className="text-[var(--ui-text-dim)]">{label}</span>
      <div className="flex overflow-hidden rounded-md border border-[var(--ui-border)]">
        {TRI_OPTIONS.map((option) => (
          <button
            key={option.value}
            type="button"
            onClick={() => onChange(option.value)}
            className={cn(
              "px-2 py-0.5 transition-colors",
              value === option.value
                ? "bg-[var(--ui-accent-bubble)] text-[var(--ui-text)]"
                : "text-[var(--ui-text-muted)] hover:bg-[var(--ui-sidebar-hover)]"
            )}
          >
            {option.label}
          </button>
        ))}
      </div>
    </div>
  )
}

function SelectFilter({
  value,
  options,
  onChange,
}: {
  value: string
  options: Array<{ value: string; label: string }>
  onChange: (value: string) => void
}) {
  return (
    <select
      value={value}
      onChange={(e) => onChange(e.target.value)}
      className="h-7 rounded-md border border-[var(--ui-border)] bg-[var(--ui-panel)] px-2 text-xs text-[var(--ui-text)] outline-none"
    >
      {options.map((option) => (
        <option key={option.value} value={option.value}>
          {option.label}
        </option>
      ))}
    </select>
  )
}

function ThreadListItem({ thread }: { thread: AgentThread }) {
  const resolveThread = useResolveAgentThread()
  const isResolved = thread.resolved === true

  const onToggleResolved = (e: React.MouseEvent) => {
    e.preventDefault()
    e.stopPropagation()
    if (resolveThread.isPending) return
    resolveThread.mutate({ threadId: thread.id, resolved: !isResolved })
  }

  return (
    <Link
      to="/agents/$threadId"
      params={{ threadId: thread.id }}
      className="group flex items-center gap-3 rounded-lg border border-transparent px-3 py-2 transition-colors hover:border-[var(--ui-border)] hover:bg-[var(--ui-sidebar-hover)]"
    >
      <div className="min-w-0 flex-1">
        <p className="truncate text-sm text-[var(--ui-text)]">{thread.title}</p>
        <p className="truncate text-[11px] text-[var(--ui-text-dim)]">
          {thread.repoFullName || "no repo"} · {thread.status}
          {isResolved ? " · resolved" : ""}
        </p>
      </div>
      <button
        type="button"
        aria-label={isResolved ? "Unresolve thread" : "Resolve thread"}
        title={isResolved ? "Unresolve thread" : "Resolve thread"}
        onClick={onToggleResolved}
        disabled={resolveThread.isPending}
        className="flex size-6 shrink-0 items-center justify-center rounded text-[var(--ui-text-dim)] hover:bg-[var(--ui-panel-2)] hover:text-[var(--ui-text)]"
      >
        {isResolved ? (
          <ArrowCounterClockwiseIcon className="size-4" />
        ) : (
          <CheckCircleIcon className="size-4" />
        )}
      </button>
    </Link>
  )
}
