import type { JSX, ReactNode } from 'react'
import {
  DataTable,
  withColumnResizing,
  withSearch,
  withSorting,
  type DataTableColumn,
} from '@overdeck/deck-ui'
import {
  Button,
  DataCoveragePanel,
  DetailDrawer,
  KvPanel,
  SectionCard,
  StatusChip,
} from '@overdeck/deck-ui'
import type { Incident } from '../../lib/incident-types'
import {
  EM_DASH,
  INCIDENT_STATE_LABEL,
  incidentCoverageGaps,
  incidentEpoch,
  incidentKvRows,
  incidentStatusToken,
  incidentTimestamp,
  type DispatchFailure,
} from './incident-view'

type Activity = Incident['activity'][number]

const ACTIVITY_COLUMNS: DataTableColumn<Activity>[] = [
  { id: 'at', header: 'When', sortable: true, sortValue: (row) => incidentEpoch(row.at) ?? -1, searchValue: (row) => row.at ?? '', minWidth: 120, cell: (row) => incidentTimestamp(row.at).relative },
  { id: 'author', header: 'Author', sortable: true, sortValue: (row) => row.username.toLowerCase(), searchValue: (row) => row.username, minWidth: 120, cell: (row) => row.username },
  { id: 'comment', header: 'Entry', sortable: true, sortValue: (row) => row.comment.toLowerCase(), searchValue: (row) => row.comment, minWidth: 240, cell: (row) => <span className="whitespace-pre-wrap">{row.comment}</span> },
]

const ACTIVITY_CAPABILITIES = [
  withSorting({ defaultSort: { columnId: 'at', direction: 'asc' } }),
  withSearch({ label: 'Search lifecycle entries' }),
  withColumnResizing(),
]

function orderedActivity(incident: Incident) {
  return [...incident.activity].sort((left, right) => {
    const byTime = (incidentEpoch(left.at) ?? 0) - (incidentEpoch(right.at) ?? 0)
    return byTime !== 0 ? byTime : left.id - right.id
  })
}

function paragraph(text: string): JSX.Element {
  const trimmed = text.trim()
  return <p className="whitespace-pre-wrap text-sm text-fg-muted">{trimmed === '' ? EM_DASH : trimmed}</p>
}

/**
 * The list route omits lifecycle comments, so the drawer renders the row it was opened
 * from and upgrades to the detail response when it arrives.
 */
export function IncidentDetailDrawer(props: {
  summary: Incident
  detail: Incident | undefined
  detailError: boolean
  dispatching: boolean
  dispatchFailure: DispatchFailure | null
  onDispatch(incidentId: string, options?: { withoutBrief?: boolean }): void
  onClose(): void
}): JSX.Element {
  const incident = props.detail ?? props.summary
  const gaps = incidentCoverageGaps(incident)

  let lifecycle: ReactNode
  if (props.detailError) {
    lifecycle = <p className="text-sm text-danger">Lifecycle history could not be loaded.</p>
  } else if (props.detail === undefined) {
    lifecycle = <p className="text-sm text-fg-muted">Loading lifecycle history…</p>
  } else {
    const activity = orderedActivity(props.detail)
    lifecycle = activity.length === 0 ? (
      <p className="text-sm text-fg-muted">No lifecycle entries recorded.</p>
    ) : (
      <div data-testid="incident-activity-table">
      <DataTable
        caption="Incident lifecycle"
        columns={ACTIVITY_COLUMNS}
        rows={activity}
        getRowId={(entry) => String(entry.id)}
        capabilities={ACTIVITY_CAPABILITIES}
      />
      </div>
    )
  }

  return (
    <DetailDrawer
      eyebrow={incident.id}
      titleId="incident-detail-title"
      onClose={props.onClose}
      title={
        <span className="flex flex-wrap items-center gap-2">
          <span>{incident.title}</span>
          <StatusChip
            status={incidentStatusToken(incident.state)}
            label={INCIDENT_STATE_LABEL[incident.state]}
          />
        </span>
      }
    >
      <div className="mt-4 space-y-4" data-testid="incident-detail-body">
        {gaps.length > 0 && (
          <div className="flex justify-end">
            <DataCoveragePanel gaps={gaps} />
          </div>
        )}

        <KvPanel rows={incidentKvRows(incident)} />

        {incident.state === 'filed' && (
          <div className="space-y-2">
            <Button disabled={props.dispatching} onClick={() => props.onDispatch(incident.id)}>
              {props.dispatching ? 'Dispatching…' : 'Dispatch incident'}
            </Button>
            {props.dispatchFailure !== null && (
              <p className="text-sm text-danger" role="alert">{props.dispatchFailure.message}</p>
            )}
            {props.dispatchFailure?.briefBlocked === true && (
              <Button
                variant="outline"
                tone="danger"
                size="sm"
                disabled={props.dispatching}
                onClick={() => props.onDispatch(incident.id, { withoutBrief: true })}
              >
                Dispatch without brief
              </Button>
            )}
          </div>
        )}

        <SectionCard title="Description">{paragraph(incident.description)}</SectionCard>

        {incident.dispatchBrief !== null && (
          <SectionCard title="Dispatch brief">
            <pre className="max-h-96 overflow-auto whitespace-pre-wrap text-sm text-fg-muted" data-testid="incident-dispatch-brief">{incident.dispatchBrief}</pre>
          </SectionCard>
        )}

        {incident.dispatchBriefProvenance !== null && (
          <SectionCard title="Dispatch brief provenance">
            {paragraph(incident.dispatchBriefProvenance)}
          </SectionCard>
        )}

        <SectionCard title="Run summary">
          {paragraph(incident.dispatch.resultSummary ?? '')}
        </SectionCard>

        <SectionCard title="Lifecycle">{lifecycle}</SectionCard>
      </div>
    </DetailDrawer>
  )
}
