import { InboxItem, SectionCard } from '@overdeck/deck-ui'
import { assignProjectColors } from '@overdeck/deck-ui/project-colors'
import { useDeckToast } from '../../lib/use-deck-toast'
import { useCallback, useState } from 'react'
import { postCollectorAction } from '../../lib/action-client'
import type { ActionRef, Item } from '../../lib/collector-types'
import { isDecisionAnswerAction, severityDotFor, triageActionsFor, WAVE4_ACTION_TOOLTIP } from './inbox-mappers'
import { actionNeedsConfirm, isGatewayActionVerb } from './inbox-actions'
import { ActionConfirmDialog } from './ActionConfirmDialog'
import { snoozeDurationMs, snoozeUntilForItem } from './inbox-snooze'
import type { ProjectColorOverrides } from './project-settings'

export interface InboxTriageRowProps {
  item: Item
  projectHex?: string
  isLast: boolean
  onSnooze: (itemId: string, until: number) => void
}

interface PendingConfirm {
  action: ActionRef
}

function ActionButton({
  action,
  busy,
  item,
  onOpen,
  onGatewayAction,
}: {
  action: ActionRef
  busy: boolean
  item: Item
  onOpen: (url: string) => void
  onGatewayAction: (action: ActionRef) => void
}) {
  const isLiveAnswer = isDecisionAnswerAction(item, action)
  if (isLiveAnswer) {
    return (
      <a
        href="/decisions"
        className="rounded-[7px] border border-[var(--mod-color-accent-tint)] bg-[var(--mod-color-accent-tint)] px-[11px] py-1 text-[11.5px] font-semibold text-accent-fg no-underline"
      >
        {action.label}
      </a>
    )
  }

  if (action.verb === 'open') {
    return (
      <button
        type="button"
        disabled={busy}
        onClick={() => onOpen(action.args.url)}
        data-action-verb={action.verb}
        className={
          action.recommended
            ? 'cursor-pointer rounded-[7px] border border-[var(--mod-color-accent-tint)] bg-[var(--mod-color-accent-tint)] px-[11px] py-1 text-[11.5px] font-semibold text-accent-fg'
            : 'cursor-pointer rounded-[7px] border border-border-strong bg-surface-raised px-[11px] py-1 text-[11.5px] text-fg'
        }
      >
        {action.label}
      </button>
    )
  }

  const gateway = isGatewayActionVerb(action.verb)
  if (!gateway) {
    return (
      <button
        type="button"
        disabled
        title={WAVE4_ACTION_TOOLTIP}
        className={
          action.recommended
            ? 'cursor-not-allowed rounded-[7px] border border-[var(--mod-color-accent-tint)] bg-[var(--mod-color-accent-tint)] px-[11px] py-1 text-[11.5px] font-semibold text-accent-fg opacity-50'
            : 'cursor-not-allowed rounded-[7px] border border-border-strong bg-surface-raised px-[11px] py-1 text-[11.5px] text-fg opacity-50'
        }
      >
        {action.label}
      </button>
    )
  }

  return (
    <button
      type="button"
      disabled={busy}
      onClick={() => onGatewayAction(action)}
      data-action-verb={action.verb}
      className={
        action.recommended
          ? 'cursor-pointer rounded-[7px] border border-[var(--mod-color-accent-tint)] bg-[var(--mod-color-accent-tint)] px-[11px] py-1 text-[11.5px] font-semibold text-accent-fg'
          : 'cursor-pointer rounded-[7px] border border-border-strong bg-surface-raised px-[11px] py-1 text-[11.5px] text-fg'
      }
    >
      {action.label}
    </button>
  )
}

/** One inbox triage row — deck-ui `InboxItem` for the body, page-local chrome for project + actions. */
export function InboxTriageRow({ item, projectHex, isLast, onSnooze }: InboxTriageRowProps) {
  const { toast } = useDeckToast()
  const actions = triageActionsFor(item)
  const [pendingConfirm, setPendingConfirm] = useState<PendingConfirm | null>(null)
  const [busy, setBusy] = useState(false)

  const runGatewayAction = useCallback(
    async (action: ActionRef) => {
      setBusy(true)
      try {
        const response = await postCollectorAction(action.verb, {
          args: action.args,
          requestedBy: item.id,
        })
        toast({
          title: `${action.label} succeeded`,
          description: typeof response.result === 'string' ? response.result : undefined,
          tone: 'success',
        })
      } catch (err) {
        const message = err instanceof Error ? err.message : String(err)
        toast({
          title: `${action.label} failed`,
          description: message,
          tone: 'danger',
        })
      } finally {
        setBusy(false)
        setPendingConfirm(null)
      }
    },
    [item.id, toast],
  )

  const onGatewayAction = useCallback(
    (action: ActionRef) => {
      if (actionNeedsConfirm(action.verb)) {
        setPendingConfirm({ action })
        return
      }
      void runGatewayAction(action)
    },
    [runGatewayAction],
  )

  const onOpen = useCallback(
    (action: ActionRef, url: string) => {
      let parsed: URL
      try {
        if (
          typeof url !== 'string'
          || Object.keys(action.args).length !== 1
          || !Object.hasOwn(action.args, 'url')
        ) throw new Error('invalid')
        parsed = new URL(url)
        if (
          parsed.protocol !== 'https:'
          || parsed.hostname !== 'github.com'
          || parsed.username !== ''
          || parsed.password !== ''
        ) throw new Error('invalid')
      } catch {
        toast({
          title: 'Open failed',
          description: 'Invalid GitHub URL',
          tone: 'danger',
        })
        return
      }
      window.location.assign(url)
    },
    [toast],
  )

  return (
    <>
      <div
        className="flex gap-2.5"
        data-inbox-item-id={item.id}
        data-inbox-kind={item.kind}
        data-inbox-severity={item.severity}
      >
        {projectHex ? (
          <span
            className="mt-2 w-1 flex-shrink-0 self-stretch rounded-full"
            style={{ backgroundColor: projectHex }}
            data-project-color={projectHex}
            aria-hidden
          />
        ) : null}
        <div className="min-w-0 flex-1">
          {item.project ? (
            <span
              className="mb-1 inline-flex items-center gap-1.5 rounded-[11px] px-2 py-0.5 text-[11.5px] font-semibold text-fg"
              style={{
                backgroundColor: projectHex ? `${projectHex}22` : undefined,
                border: projectHex ? `1px solid ${projectHex}55` : '1px solid var(--mod-color-border)',
              }}
              data-project-tag={item.project}
              data-project-color={projectHex}
            >
              {projectHex ? (
                <span className="h-[7px] w-[7px] rounded-full" style={{ backgroundColor: projectHex }} aria-hidden />
              ) : null}
              {item.project}
            </span>
          ) : null}
          <div className="flex items-start gap-2.5">
            <div className="min-w-0 flex-1">
              <InboxItem dot={severityDotFor(item.severity)} title={item.title} subtitle={item.detail} actions={[]} isLast={isLast} />
            </div>
            <div className="ml-auto flex flex-shrink-0 gap-1.5 pt-2.5">
              {actions.map((action) => (
                <ActionButton
                  key={`${action.verb}:${action.label}`}
                  action={action}
                  busy={busy}
                  item={item}
                  onOpen={(url) => onOpen(action, url)}
                  onGatewayAction={onGatewayAction}
                />
              ))}
              <button
                type="button"
                onClick={() => onSnooze(item.id, snoozeUntilForItem(item.ts, snoozeDurationMs()))}
                className="cursor-pointer rounded-[7px] border border-border-strong bg-surface-raised px-[11px] py-1 text-[11.5px] text-fg"
              >
                Snooze
              </button>
            </div>
          </div>
        </div>
      </div>
      {pendingConfirm ? (
        <ActionConfirmDialog
          itemTitle={item.title}
          action={pendingConfirm.action}
          open
          busy={busy}
          onConfirm={() => void runGatewayAction(pendingConfirm.action)}
          onCancel={() => {
            if (!busy) setPendingConfirm(null)
          }}
        />
      ) : null}
    </>
  )
}

export function projectColorMap(items: Item[], overrides: ProjectColorOverrides): Record<string, string> {
  const ids = [...new Set(items.map((item) => item.project).filter((id): id is string => Boolean(id)))].sort()
  const assigned = assignProjectColors(ids, overrides)
  return Object.fromEntries(ids.map((id) => [id, assigned[id]!.hex]))
}

export { SectionCard }
