import { Button, DetailDrawer, formatRelativeTime, safeHttpUrl, useDeckTooltip } from '@overdeck/deck-ui'
import { useState, type JSX } from 'react'
import { useRequestStory } from '../../lib/collector-queries'
import { openSessionTerminal } from '../sessions/session-terminal'
import type { RequestRow, RequestStoryEvent } from '../../lib/request-types'
import { RequestAnswerForm } from './RequestAnswerForm'
import { RequestWorkEvidence } from './RequestWorkEvidence'
import { RequestDeliveryEvidence } from './RequestDeliveryEvidence'

function Timestamp({ at }: { at: string }): JSX.Element {
  const parsed = Date.parse(at)
  const absolute = Number.isNaN(parsed) ? at : new Date(parsed).toLocaleString()
  const tooltip = useDeckTooltip(absolute, 'Recorded at')
  return <time dateTime={at} className="requests-drawer-time" {...tooltip}>{Number.isNaN(parsed) ? at : formatRelativeTime(parsed)}</time>
}

function activitySummary(row: RequestRow): string {
  if (row.state === 'blocked_needs_owner') {
    return row.detail
      ? `${row.detail} This is waiting for your answer; everything else can keep moving.`
      : 'This is waiting for your answer, but the question was not recorded.'
  }
  if (row.state === 'orphaned') {
    return row.detail
      ? `${row.detail} This request needs recovery.`
      : 'The worker stopped and this request needs recovery.'
  }
  if (row.detail) return `${row.detail} You do not need to act right now.`
  switch (row.state) {
    case 'asked': return 'This is waiting in the intake queue. You do not need to act right now.'
    case 'in_flight': return 'Work is moving, but the latest detail was not recorded. You do not need to act right now.'
    case 'shipped': return row.proof_url
      ? 'This was shipped and has recorded proof. You do not need to act.'
      : 'This was marked shipped, but proof was not recorded. You do not need to act.'
    case 'canceled': return 'This request was canceled.'
  }
}

export function factoryActivityUrl(proofUrl: string | null): string | null {
  if (!proofUrl) return null
  try {
    const pathname = new URL(proofUrl, 'http://overdeck.local').pathname
    return /^\/factory\/[^/]+(?:\/agents\/[^/]+)?$/.test(pathname) ? pathname : null
  } catch {
    return null
  }
}

function sourceLabel(sourceId: string): string {
  const labels: Record<string, string> = {
    'request-events': 'Request history',
    'request-registry': 'Request registry',
    'legacy-request-registry': 'Earlier request records',
    'legacy-request-transitions': 'Earlier status records',
    'legacy-receipt-trail': 'Earlier activity records',
    'request-hook': 'Request hook',
    'claude-skill-hook': 'Claude request hook',
    'claude-task-hook': 'Claude task hook',
    'claude-owner-question-hook': 'Owner question hook',
    'od-requests-cli': 'Requests command',
    'request-fire': 'Automated incident intake',
    'factory-trace': 'Factory work record',
    'local-gate': 'Verification record',
    'claude-tool-hook': 'Session tool record',
  }
  return labels[sourceId] ?? sourceId
}

function coverageStatusLabel(status: string): string {
  return status === 'complete' ? 'Complete' : status === 'partial' ? 'Partial' : status === 'unavailable' ? 'Unavailable' : status === 'stale' ? 'Stale' : 'Waiting for delivery'
}

function actorLabel(event: RequestStoryEvent): string {
  if (event.actor.displayName) return event.actor.displayName
  switch (event.actor.type) {
    case 'owner': return 'You'
    case 'agent': return 'Agent'
    case 'machinery': return 'Overdeck'
    case 'unknown': return 'Actor not recorded'
  }
}

function ActivityEntry({ entry }: { entry: RequestStoryEvent }): JSX.Element {
  const actor = actorLabel(entry)
  return (
    <li className="requests-activity-entry">
      <span aria-hidden="true" className={`requests-activity-dot requests-activity-dot--${entry.kind}`} />
      <div>
        <p>{entry.summary}</p>
        <div className="requests-activity-meta">
          {entry.sessionId ? <button type="button" onClick={() => openSessionTerminal(entry.sessionId!)}>{actor}</button> : <span>{actor}</span>}
          {entry.hostId ? <span>Host: {entry.hostId}</span> : null}
          {entry.accountId ? <span>Account: {entry.accountId}</span> : null}
          <Timestamp at={entry.occurredAt} />
          {entry.legacy ? <span>Earlier record · partial detail</span> : null}
        </div>
      </div>
    </li>
  )
}

export function RequestDrawer({ request, onClose, onAnswered }: { request: RequestRow; onClose(): void; onAnswered?(row: RequestRow): void }): JSX.Element {
  const storyQuery = useRequestStory(request.id)
  const story = storyQuery.data?.story
  const originalCoverage = story?.coverage.find((item) => item.fact === 'original_request')
  const activityCoverage = story?.coverage.find((item) => item.fact === 'activity')
  const deliveryCoverage = story?.coverage.filter((item) => item.fact === 'activity_delivery') ?? []
  const workCoverage = story?.coverage.find((item) => item.fact === 'work_evidence')
  const requestDeliveryCoverage = story?.coverage.find((item) => item.fact === 'delivery_evidence')
  const proofUrl = request.proof_url ? safeHttpUrl(request.proof_url) : null
  const activityUrl = factoryActivityUrl(request.proof_url)
  const [answering, setAnswering] = useState(false)
  const [answerError, setAnswerError] = useState<string>()

  return (
    <DetailDrawer eyebrow={request.project} title={request.title} titleId="request-detail-title" modal={false} onClose={onClose}>
      <div className="requests-drawer">
        <section className="requests-drawer-request" aria-labelledby="request-original">
          <h3 id="request-original">Your original request</h3>
          {storyQuery.isPending ? <p className="requests-drawer-gap">Loading the recorded request…</p> : null}
          {storyQuery.isError ? <p className="requests-drawer-gap">The request record could not be loaded.</p> : null}
          {story?.originalRequest.body ? (
            <p className="requests-original-body">{story.originalRequest.body}</p>
          ) : story ? (
            <p className="requests-drawer-gap">The full original request was not recorded. The card title is only a summary.</p>
          ) : null}
          <Timestamp at={story?.askedAt ?? request.asked_at} />
          {originalCoverage ? (
            <p className="requests-drawer-gap">{sourceLabel(originalCoverage.sourceId)} · {coverageStatusLabel(originalCoverage.status)}{originalCoverage.reason ? ` — ${originalCoverage.reason}` : ''}</p>
          ) : null}
        </section>

        <section aria-labelledby="request-happening">
          <h3 id="request-happening">What’s happening</h3>
          <p className="requests-status-story">{activitySummary(request)}</p>
        </section>

        <section aria-labelledby="request-activity">
          <h3 id="request-activity">Activity story</h3>
          {storyQuery.isPending ? (
            <p className="requests-drawer-gap">Loading recorded activity…</p>
          ) : storyQuery.isError ? (
            <p className="requests-drawer-gap">Recorded activity could not be loaded.</p>
          ) : !story || story.events.length === 0 ? (
            <p className="requests-drawer-gap">No recorded activity yet.</p>
          ) : (
            <ol className="requests-activity-list">{story.events.map((entry) => <ActivityEntry key={entry.id} entry={entry} />)}</ol>
          )}
          {activityCoverage ? (
            <p className="requests-drawer-gap">{sourceLabel(activityCoverage.sourceId)} · {coverageStatusLabel(activityCoverage.status)}{activityCoverage.reason ? ` — ${activityCoverage.reason}` : ''}</p>
          ) : null}
          {deliveryCoverage.map((coverage) => (
            <p className="requests-drawer-gap" key={`delivery-${coverage.sourceId}`}>
              {sourceLabel(coverage.sourceId)} delivery · {coverageStatusLabel(coverage.status)}{coverage.reason ? ` — ${coverage.reason}` : ''}
            </p>
          ))}
        </section>

        {story ? <RequestWorkEvidence requestId={request.id} links={story.links} attachments={story.attachments} coverage={workCoverage} /> : null}
        {story ? <RequestDeliveryEvidence links={story.links} coverage={requestDeliveryCoverage} /> : null}

        <section aria-labelledby="request-links">
          <h3 id="request-links">Links out</h3>
          <div className="requests-drawer-links">
            {request.plan_ref ? <span>Spec: {request.plan_ref}</span> : null}
            {activityUrl ? <a href={activityUrl}>Open activity</a> : null}
            {proofUrl ? <a href={proofUrl}>Deployed proof ↗</a> : null}
          </div>
          {!request.plan_ref && !activityUrl && !proofUrl ? <p className="requests-drawer-gap">Spec, branch, landing, and proof links were not recorded.</p> : null}
        </section>

        <section aria-labelledby="request-repeated-asks">
          <h3 id="request-repeated-asks">Repeated asks</h3>
          <p className="requests-drawer-gap">Repeated-ask history is not recorded yet.</p>
        </section>

        <section className="requests-drawer-actions" aria-labelledby="request-actions">
          <h3 id="request-actions">Actions</h3>
          {request.state === 'blocked_needs_owner' ? (
            answering ? (
              <RequestAnswerForm
                request={request}
                error={answerError}
                onSuccess={(row) => { setAnswerError(undefined); onAnswered?.(row) }}
                onError={setAnswerError}
              />
            ) : <Button size="sm" onClick={() => setAnswering(true)}>Answer</Button>
          ) : <p className="requests-drawer-gap">No action is needed from you.</p>}
          <p className="requests-drawer-gap">Priority, cancel, and correction actions are not available from the request registry yet.</p>
          <p className="requests-journal-note">Every available action is journaled.</p>
        </section>
      </div>
    </DetailDrawer>
  )
}
