"use client"

import * as React from "react"

import { JobDescriptionForm } from "@/components/job-description-form"
import { useT } from "@/components/locale-provider"
import { Badge } from "@/components/ui/badge"
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetHeader,
  SheetTitle,
} from "@/components/ui/sheet"
import { OCCURRENCE_WORD } from "@/lib/i18n/duty-words"
import type { Occurrence } from "@/lib/task-form"
import { ownJobDescription } from "@/lib/job-description-view"
import { loadPosition, saveJobDescription } from "./actions"
import type { EditablePosition } from "./actions"

/**
 * Writing a job description without leaving the list of the ones still missing.
 *
 * One sheet for the whole table rather than one per row: 194 rows would
 * otherwise each carry a panel that is almost never opened. The table owns
 * which position is being edited and this draws it.
 *
 * The position is fetched when the panel opens instead of travelling with the
 * table. Only whoever opened it wants the text, and sending 193 paragraphs to
 * draw a column of badges would make the page heavier with every description
 * the client writes — the opposite of what this screen is for.
 *
 * The duties are shown beside the textarea because a job is easier to describe
 * with its own work in front of you, and because they are the other half of
 * what the next holder will read.
 */
export function JobDescriptionSheet({
  positionId,
  onClose,
}: {
  /** Null when nothing is being edited, which is when the sheet is shut. */
  positionId: string | null
  onClose: () => void
}) {
  const t = useT()

  /**
   * What came back, and which position it came back for.
   *
   * The id is stored beside the answer so that everything else can be derived
   * during render rather than corrected in an effect. Clearing the old position
   * with a `setState` when the panel opens on a new one is the pattern
   * `people-search.tsx` documents as the wrong one: it renders once with the
   * previous answer and again with the new, and here the first of those two
   * renders would show one position's description under another's title.
   */
  const [loaded, setLoaded] = React.useState<{
    id: string
    data: EditablePosition | null
  } | null>(null)

  React.useEffect(() => {
    if (!positionId) return

    // `stale` rather than an AbortController: a server action cannot be
    // aborted, and what matters is only that a slow answer for a position
    // somebody has already closed does not overwrite a fast one.
    let stale = false
    void loadPosition(positionId).then((data) => {
      if (!stale) setLoaded({ id: positionId, data })
    })

    return () => {
      stale = true
    }
  }, [positionId])

  const answered = loaded !== null && loaded.id === positionId
  const position = answered ? loaded.data : null
  const loading = positionId !== null && !answered

  const own = position
    ? ownJobDescription({
        jobDescription: position.jobDescription,
        duties: position.duties,
      })
    : null

  return (
    <Sheet
      open={positionId !== null}
      onOpenChange={(open) => !open && onClose()}
    >
      <SheetContent
        side="right"
        className="w-full gap-6 overflow-y-auto sm:max-w-xl"
      >
        <SheetHeader>
          <SheetTitle>{position?.title ?? ""}</SheetTitle>
          <SheetDescription>
            {position?.department ?? (loading ? t("action.working") : "")}
          </SheetDescription>
        </SheetHeader>

        {position && positionId ? (
          <div className="flex flex-col gap-6 px-4 pb-4">
            <div className="flex flex-col gap-2">
              <p className="font-medium">{t("position.jobDescription")}</p>
              <p className="text-sm text-foreground/70">
                {t("position.jobDescriptionHint")}
              </p>
              {/*
                Keyed on the position so that opening a second one after the
                first does not keep the first one's draft in the textarea. The
                form holds the draft in state, and state survives a prop change.
              */}
              <JobDescriptionForm
                key={positionId}
                positionId={positionId}
                text={position.jobDescription}
                action={saveJobDescription}
                autoFocus
                onSaved={onClose}
                onCancel={onClose}
              />
            </div>

            <Duties
              title={t("myJobDescription.listed")}
              duties={own?.listed ?? []}
              schedule={false}
            />
            <Duties
              title={t("myJobDescription.generated")}
              duties={own?.generated ?? []}
              schedule
            />
          </div>
        ) : null}
      </SheetContent>
    </Sheet>
  )
}

/** The same two lists the staff screen draws, read-only and for context here. */
function Duties({
  title,
  duties,
  schedule,
}: {
  title: string
  duties: EditablePosition["duties"]
  schedule: boolean
}) {
  const t = useT()
  if (duties.length === 0) return null

  return (
    <section className="flex flex-col gap-2">
      <p className="font-medium">{title}</p>
      <ul className="flex flex-col gap-2">
        {duties.map((duty) => (
          <li
            key={duty.id}
            className="flex items-baseline justify-between gap-4 border-b pb-2 text-sm last:border-b-0"
          >
            <span>{duty.description}</span>
            {schedule ? (
              <Badge variant="outline" className="shrink-0">
                {t(OCCURRENCE_WORD[duty.occurrence as Occurrence])}
              </Badge>
            ) : null}
          </li>
        ))}
      </ul>
    </section>
  )
}
