"use client"

import * as React from "react"
import Link from "next/link"
import { IconChevronRight } from "@tabler/icons-react"

import { useLocale, useT } from "@/components/locale-provider"
import { Badge } from "@/components/ui/badge"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"
import { dayAndMonth, shortDay } from "@/lib/i18n/dates"
import type { Locale } from "@/lib/i18n"
import type { TaskRow } from "@/lib/services/tasks"
import type { Run } from "@/lib/team-view"
import { STATUS } from "./columns"

/**
 * The backlog, one line per duty.
 *
 * Only this half of My tasks is grouped, and the asymmetry is the point. Today
 * is a handful of rows and every one of them is a different thing to do, so
 * collapsing them would hide the list behind a click and save nobody a scroll.
 * What repeats is the debt: a daily check missed nine days running is one duty
 * and nine dates, and ungrouped it took nine rows and pushed today's actual
 * work off the first screen.
 *
 * Grouping is not hiding. The count is on the collapsed line, so the size of
 * what is owed is on screen without opening anything, and every date inside is
 * still its own task with its own link. Nothing here writes work off: the
 * client answered on 4 August that work owed is work owed.
 *
 * Not a `DataTable`. The rows come in two shapes, a duty and a date under it,
 * and TanStack would need one column set covering both. The same `Table`
 * primitives the other lists are built from, so it reads as the same furniture
 * as the team overview's grouped Late tab, which solved this first.
 */
export function CarriedOverTable({ groups }: { groups: Run<TaskRow>[] }) {
  const t = useT()
  const locale = useLocale()
  const [open, setOpen] = React.useState<ReadonlySet<string>>(new Set())

  const toggle = (key: string) => {
    setOpen((was) => {
      const next = new Set(was)
      if (!next.delete(key)) next.add(key)
      return next
    })
  }

  return (
    <div className="overflow-hidden rounded-xl ring-1 ring-foreground/10">
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead>{t("team.duty")}</TableHead>
            <TableHead>{t("tasks.due")}</TableHead>
            <TableHead className="text-right">{t("tasks.dates")}</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {groups.map((group, index) => {
            const shown = open.has(group.key)
            // The position in the list rather than the group's own key, which is
            // a template id: `aria-controls` takes a space-separated list of
            // ids, and an id from data is an id that can one day contain a
            // space and send the browser looking for two elements.
            const panel = `carried-over-panel-${index}`
            return (
              <React.Fragment key={group.key}>
                <TableRow>
                  <TableCell>
                    <button
                      type="button"
                      onClick={() => toggle(group.key)}
                      aria-expanded={shown}
                      aria-controls={panel}
                      aria-label={
                        shown ? t("team.hideDates") : t("team.showDates")
                      }
                      className="-m-1 flex items-start gap-2 rounded-lg p-1 text-left outline-none focus-visible:ring-3 focus-visible:ring-ring/50"
                    >
                      <IconChevronRight
                        className={`mt-0.5 size-4 shrink-0 transition-transform ${
                          shown ? "rotate-90" : ""
                        }`}
                      />
                      <span>{group.description}</span>
                    </button>
                  </TableCell>
                  <TableCell className="tabular-nums">
                    {runWindow(group, locale)}
                  </TableCell>
                  <TableCell className="text-right">
                    <Badge variant="destructive">
                      {group.rows.length === 1
                        ? t("team.dateOne")
                        : t("team.dates", { count: group.rows.length })}
                    </Badge>
                  </TableCell>
                </TableRow>
                {shown ? (
                  <TableRow id={panel}>
                    <TableCell colSpan={3} className="bg-muted/30">
                      {/*
                        Each date leads into its own task, where the acts live.
                        A missed task offers its assignee Finish first and Start
                        under it, and the reader of this list is the assignee of
                        every row in it, so the work can still be handed in from
                        here in two presses.
                      */}
                      <ul className="flex flex-col gap-1 ps-8">
                        {group.rows.map((row) => (
                          <li key={row.id} className="flex items-center gap-3">
                            <Link
                              href={`/tasks/${row.id}`}
                              aria-label={t("team.openTask")}
                              className="tabular-nums hover:underline"
                            >
                              {shortDay(row.dueDate, locale)}
                            </Link>
                            <Badge variant={STATUS[row.status].variant}>
                              {t(STATUS[row.status].label)}
                            </Badge>
                            {row.late ? (
                              <Badge variant="destructive">
                                {t("status.late")}
                              </Badge>
                            ) : null}
                          </li>
                        ))}
                      </ul>
                    </TableCell>
                  </TableRow>
                ) : null}
              </React.Fragment>
            )
          })}
        </TableBody>
      </Table>
    </div>
  )
}

/**
 * The run, as one phrase. A group of one is one date and not an arrow between a
 * day and itself.
 */
function runWindow(group: Run<TaskRow>, locale: Locale): string {
  const from = dayAndMonth(group.from, locale)
  if (group.from === group.to) return from
  return `${from} → ${dayAndMonth(group.to, locale)}`
}
