"use client";

import { useState } from "react";
import { useAccount, useSignMessage, useSignTypedData } from "wagmi";
import type { PendingRequest, TransactionParams } from "@/lib/types";
import { formatEther, type Hex } from "viem";

interface RequestCardProps {
  request: PendingRequest;
  onRespond: (id: string, result?: string, error?: { code: number; message: string }) => void;
}

export default function RequestCard({ request, onRespond }: RequestCardProps) {
  const [signing, setSigning] = useState(false);
  const { address, connector } = useAccount();
  const { signMessageAsync } = useSignMessage();
  const { signTypedDataAsync } = useSignTypedData();

  const handleApprove = async () => {
    if (!address) return;
    setSigning(true);

    try {
      let result: string;

      switch (request.method) {
        case "eth_sendTransaction": {
          if (!connector) throw new Error("Wallet not connected");
          const txParams = (Array.isArray(request.params) ? request.params[0] : request.params) as TransactionParams;
          // Get the raw EIP-1193 provider (e.g. window.ethereum) directly from
          // the connector, fully bypassing viem/wagmi's transport layer
          const provider = await connector.getProvider() as { request: (args: { method: string; params: unknown[] }) => Promise<string> };
          // Strip undefined/null/empty fields — MetaMask rejects keys like `to: undefined`
          // (contract deployments legitimately have no `to`)
          // Pass through all fields from the original request as-is,
          // only omitting keys that are truly absent (undefined/null).
          // Map `input` → `data` (forge/geth use `input`, MetaMask expects `data`)
          const raw: Record<string, unknown> = { from: address, ...txParams };
          if (raw.input && !raw.data) {
            raw.data = raw.input;
          }
          delete raw.input;
          const tx: Record<string, string> = {};
          for (const [k, v] of Object.entries(raw)) {
            if (v != null && v !== "") tx[k] = String(v);
          }
          console.log("[prpc] eth_sendTransaction params:", JSON.stringify(tx, null, 2));
          result = await provider.request({
            method: "eth_sendTransaction",
            params: [tx],
          });
          break;
        }
        case "personal_sign": {
          const params = request.params as string[];
          // personal_sign params: [message, address]
          const message = params[0];
          result = await signMessageAsync({ message: { raw: message as Hex } });
          break;
        }
        case "eth_sign": {
          const params = request.params as string[];
          // eth_sign params: [address, message]
          const message = params[1];
          result = await signMessageAsync({ message: { raw: message as Hex } });
          break;
        }
        case "eth_signTypedData":
        case "eth_signTypedData_v3":
        case "eth_signTypedData_v4": {
          const params = request.params as [string, string | object];
          const typedData = typeof params[1] === "string" ? JSON.parse(params[1]) : params[1];
          result = await signTypedDataAsync({
            domain: typedData.domain,
            types: typedData.types,
            primaryType: typedData.primaryType,
            message: typedData.message,
          });
          break;
        }
        case "eth_signTransaction": {
          // eth_signTransaction is less commonly supported by wallets via wagmi
          // We'll return an error suggesting eth_sendTransaction instead
          onRespond(request.id, undefined, {
            code: -32601,
            message: "eth_signTransaction not supported. Use eth_sendTransaction instead.",
          });
          setSigning(false);
          return;
        }
        default:
          onRespond(request.id, undefined, {
            code: -32601,
            message: `Unsupported method: ${request.method}`,
          });
          setSigning(false);
          return;
      }

      onRespond(request.id, result);
    } catch (err: unknown) {
      const message = err instanceof Error ? err.message : "User rejected or signing failed";
      onRespond(request.id, undefined, { code: 4001, message });
    } finally {
      setSigning(false);
    }
  };

  const handleReject = () => {
    onRespond(request.id, undefined, { code: 4001, message: "User rejected the request" });
  };

  return (
    <div className="rounded-xl border border-zinc-200 bg-white p-5 shadow-sm dark:border-zinc-800 dark:bg-zinc-900">
      {/* Header */}
      <div className="mb-4 flex items-center justify-between">
        <div className="flex items-center gap-2">
          <span className="rounded-md bg-amber-100 px-2.5 py-1 text-xs font-semibold text-amber-800 dark:bg-amber-900/30 dark:text-amber-400">
            {request.method}
          </span>
          <span className="text-xs text-zinc-400">
            {new Date(request.receivedAt).toLocaleTimeString()}
          </span>
        </div>
        <span className="font-mono text-xs text-zinc-400">
          {request.id.slice(0, 8)}...
        </span>
      </div>

      {/* Params */}
      <div className="mb-4">
        <ParamsDisplay method={request.method} params={request.params} />
      </div>

      {/* Actions */}
      <div className="flex gap-3">
        <button
          onClick={handleReject}
          disabled={signing}
          className="flex-1 rounded-lg border border-zinc-200 px-4 py-2.5 text-sm font-medium text-zinc-700 transition-colors hover:bg-zinc-50 disabled:opacity-50 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800"
        >
          Reject
        </button>
        <button
          onClick={handleApprove}
          disabled={signing || !address || !connector}
          className="flex-1 rounded-lg bg-emerald-600 px-4 py-2.5 text-sm font-medium text-white transition-colors hover:bg-emerald-500 disabled:opacity-50"
        >
          {signing ? "Signing..." : "Approve & Sign"}
        </button>
      </div>
    </div>
  );
}

function ParamsDisplay({ method, params }: { method: string; params: unknown }) {
  if (method === "eth_sendTransaction" || method === "eth_signTransaction") {
    const tx = (Array.isArray(params) ? params[0] : params) as TransactionParams;
    const calldata = tx.data || tx.input;
    const isDeployment = !tx.to;
    return (
      <div className="space-y-2 rounded-lg bg-zinc-50 p-3 dark:bg-zinc-800/50">
        {tx.nonce && (
          <Row label="Nonce" value={BigInt(tx.nonce).toString()} mono />
        )}
        {isDeployment && (
          <Row label="Type" value="Contract Deployment" />
        )}
        {tx.to && (
          <Row label="To" value={tx.to} mono />
        )}
        {tx.value && tx.value !== "0x0" && (
          <Row label="Value" value={`${formatEther(BigInt(tx.value))} ETH`} />
        )}
        {calldata && calldata !== "0x" && (
          <Row
            label={isDeployment ? "Bytecode" : "Data"}
            value={calldata.length > 66 ? `${calldata.slice(0, 66)}...` : calldata}
            mono
          />
        )}
        {tx.gas && (
          <Row label="Gas Limit" value={BigInt(tx.gas).toString()} />
        )}
      </div>
    );
  }

  if (method === "personal_sign") {
    const msg = (params as string[])[0];
    let decoded: string;
    try {
      // Try to decode hex to utf-8
      decoded = Buffer.from(msg.replace("0x", ""), "hex").toString("utf-8");
    } catch {
      decoded = msg;
    }
    return (
      <div className="rounded-lg bg-zinc-50 p-3 dark:bg-zinc-800/50">
        <Row label="Message" value={decoded} />
      </div>
    );
  }

  if (method.startsWith("eth_signTypedData")) {
    const raw = (params as [string, string | object])[1];
    const typedData = typeof raw === "string" ? JSON.parse(raw) : raw;
    return (
      <div className="rounded-lg bg-zinc-50 p-3 dark:bg-zinc-800/50">
        <p className="mb-1 text-xs font-medium text-zinc-500 dark:text-zinc-400">
          Typed Data ({typedData.primaryType})
        </p>
        <pre className="max-h-48 overflow-auto whitespace-pre-wrap text-xs text-zinc-700 dark:text-zinc-300">
          {JSON.stringify(typedData.message, null, 2)}
        </pre>
      </div>
    );
  }

  // Fallback: show raw JSON
  return (
    <div className="rounded-lg bg-zinc-50 p-3 dark:bg-zinc-800/50">
      <pre className="max-h-48 overflow-auto whitespace-pre-wrap text-xs text-zinc-700 dark:text-zinc-300">
        {JSON.stringify(params, null, 2)}
      </pre>
    </div>
  );
}

function Row({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
  return (
    <div className="flex items-baseline justify-between gap-4">
      <span className="shrink-0 text-xs font-medium text-zinc-500 dark:text-zinc-400">
        {label}
      </span>
      <span
        className={`truncate text-sm text-zinc-800 dark:text-zinc-200 ${
          mono ? "font-mono" : ""
        }`}
      >
        {value}
      </span>
    </div>
  );
}
