import { useState } from 'react';
import { Check, FolderOpen, ShieldOff } from 'lucide-react';
import { toast } from 'sonner';
import { api } from '@/api/client';
import { Button } from '@/components/ui/button';
import type { ToolCall, ToolResult } from '@/api/types';

// v1.13.17-cross-repo-reads. Renders an inline allow/deny picker for a
// paused request_read_access tool call. Mirrors AskUserInputCard's pending
// vs answered render dance:
//   - Pending: server pre-stamps a sentinel tool_result with output=null.
//     The card shows path + reason and lets the user pick Allow or Deny.
//   - Answered: the eventual WS tool_result frame carries the actual
//     decision string ("granted: <root>" or "denied" or "denied: <reason>").
//     The card flips to a read-only summary line.
//
// Tool name discrimination lives in MessageList.flatten/group — anything
// with tc.name === 'request_read_access' bypasses grouping and renders this
// card directly.

interface Props {
  toolCall: ToolCall;
  toolResult: ToolResult | null;
  chatId: string;
}

interface ParsedArgs {
  path: string;
  reason: string;
}

function parseArgs(raw: unknown): ParsedArgs | null {
  if (!raw || typeof raw !== 'object') return null;
  const obj = raw as { path?: unknown; reason?: unknown };
  if (typeof obj.path !== 'string' || obj.path.length === 0) return null;
  if (typeof obj.reason !== 'string' || obj.reason.length === 0) return null;
  return { path: obj.path, reason: obj.reason };
}

function decisionVariant(output: unknown): 'granted' | 'denied' | 'unknown' {
  if (typeof output !== 'string') return 'unknown';
  if (output.startsWith('granted:')) return 'granted';
  if (output === 'denied' || output.startsWith('denied:')) return 'denied';
  return 'unknown';
}

export function RequestReadAccessCard({ toolCall, toolResult, chatId }: Props) {
  const args = parseArgs(toolCall.args);

  if (!args) {
    return (
      <div className="rounded border border-destructive/40 bg-destructive/10 text-xs px-3 py-2 text-destructive">
        request_read_access: malformed tool args
      </div>
    );
  }

  // Non-null output means the WS tool_result frame arrived (or the row was
  // re-fetched from history).
  const answered = toolResult && toolResult.output !== null;
  if (answered) {
    return <AnsweredView args={args} output={toolResult!.output} />;
  }

  return <PendingView args={args} toolCallId={toolCall.id} chatId={chatId} />;
}

function PendingView({
  args,
  toolCallId,
  chatId,
}: {
  args: ParsedArgs;
  toolCallId: string;
  chatId: string;
}) {
  const [submitting, setSubmitting] = useState<'allow' | 'deny' | null>(null);

  async function decide(decision: 'allow' | 'deny') {
    if (submitting) return;
    setSubmitting(decision);
    try {
      await api.chats.grantReadAccess(chatId, toolCallId, decision);
      // Card stays mounted; the incoming WS tool_result frame swaps it to
      // AnsweredView via the parent prop change.
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'request failed');
      setSubmitting(null);
    }
  }

  return (
    <div className="rounded-lg border border-amber-500/40 bg-amber-500/5 text-sm">
      <div className="px-4 py-3 space-y-2">
        <div className="flex items-center gap-2 text-xs uppercase tracking-wide text-amber-700 dark:text-amber-300">
          <ShieldOff className="size-3.5" />
          <span>Read-access request</span>
        </div>
        <div className="space-y-1.5">
          <div className="text-[10px] uppercase tracking-wide text-muted-foreground/70">Path</div>
          <div className="font-mono text-xs break-all rounded bg-background/60 border px-2 py-1">
            {args.path}
          </div>
        </div>
        <div className="space-y-1.5">
          <div className="text-[10px] uppercase tracking-wide text-muted-foreground/70">Reason</div>
          <div className="text-sm leading-snug whitespace-pre-wrap">{args.reason}</div>
        </div>
        <div className="text-[11px] text-muted-foreground pt-1">
          Allow grants the agent read access to the matching repository root for
          the rest of this session. Revoke any time from the session settings.
        </div>
      </div>
      <div className="flex justify-end gap-2 border-t border-amber-500/20 px-4 py-2">
        <Button
          type="button"
          size="sm"
          variant="outline"
          disabled={submitting !== null}
          onClick={() => void decide('deny')}
        >
          {submitting === 'deny' ? 'Denying…' : 'Deny'}
        </Button>
        <Button
          type="button"
          size="sm"
          disabled={submitting !== null}
          onClick={() => void decide('allow')}
        >
          {submitting === 'allow' ? 'Allowing…' : 'Allow'}
        </Button>
      </div>
    </div>
  );
}

function AnsweredView({ args, output }: { args: ParsedArgs; output: unknown }) {
  const variant = decisionVariant(output);
  const text = typeof output === 'string' ? output : 'unknown';

  return (
    <div
      className={
        variant === 'granted'
          ? 'rounded-lg border border-emerald-500/40 bg-emerald-500/5 text-sm'
          : variant === 'denied'
            ? 'rounded-lg border bg-muted/20 text-sm'
            : 'rounded-lg border border-destructive/40 bg-destructive/5 text-sm'
      }
    >
      <div className="px-4 py-3 space-y-2">
        <div className="flex items-center gap-2 text-xs uppercase tracking-wide">
          {variant === 'granted' ? (
            <>
              <Check className="size-3.5 text-emerald-600" />
              <span className="text-emerald-700 dark:text-emerald-300">Read access granted</span>
            </>
          ) : variant === 'denied' ? (
            <>
              <ShieldOff className="size-3.5 text-muted-foreground" />
              <span className="text-muted-foreground">Read access denied</span>
            </>
          ) : (
            <>
              <ShieldOff className="size-3.5 text-destructive" />
              <span className="text-destructive">Read access request — unknown result</span>
            </>
          )}
        </div>
        <div className="space-y-1.5">
          <div className="text-[10px] uppercase tracking-wide text-muted-foreground/70">Path</div>
          <div className="font-mono text-xs break-all rounded bg-background/60 border px-2 py-1">
            {args.path}
          </div>
        </div>
        {variant === 'granted' && (
          <div className="space-y-1.5">
            <div className="text-[10px] uppercase tracking-wide text-muted-foreground/70">Granted root</div>
            <div className="font-mono text-xs break-all rounded bg-background/60 border px-2 py-1 flex items-center gap-1.5">
              <FolderOpen className="size-3 shrink-0 text-muted-foreground" />
              <span>{text.replace(/^granted:\s*/, '')}</span>
            </div>
          </div>
        )}
        {variant === 'denied' && text !== 'denied' && (
          <div className="text-[11px] text-muted-foreground">
            {text.replace(/^denied:\s*/, '')}
          </div>
        )}
      </div>
    </div>
  );
}
