"use client";

import { useParams } from "next/navigation";
import { useCallback, useEffect, useState } from "react";

import { api } from "@/lib/api/client";
import type { components } from "@/lib/api/schema";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";

type Proposal = components["schemas"]["ChangeProposalRead"];
type Op = { op: string; entity_type: string; entity_id?: string | null; payload?: Record<string, unknown> };

const STATUS_STYLE: Record<string, string> = {
  pending: "border-bronze/40 text-bronze",
  applied: "border-green-600/40 text-green-700 dark:text-green-400",
  rejected: "border-[var(--border)] text-[var(--muted)]",
};

export default function ProposalsPage() {
  const { id: treeId } = useParams<{ id: string }>();
  const [proposals, setProposals] = useState<Proposal[]>([]);
  const [meRole, setMeRole] = useState<string | null>(null);
  const [ready, setReady] = useState(false);
  const [busy, setBusy] = useState<string | null>(null);

  const load = useCallback(async () => {
    const [props, me, members] = await Promise.all([
      api.GET("/api/v1/trees/{tree_id}/proposals", { params: { path: { tree_id: treeId } } }),
      api.GET("/api/v1/users/me"),
      api.GET("/api/v1/trees/{tree_id}/members", { params: { path: { tree_id: treeId } } }),
    ]);
    const myId = me.data?.id;
    setMeRole((members.data ?? []).find((m) => m.user_id === myId)?.role ?? null);
    setProposals(props.data ?? []);
    setReady(true);
  }, [treeId]);

  useEffect(() => {
    load();
  }, [load]);

  const canReview = meRole === "owner" || meRole === "editor";

  async function act(pid: string, action: "apply" | "reject") {
    setBusy(pid);
    const { error, response } = await api.POST(
      `/api/v1/trees/{tree_id}/proposals/{proposal_id}/${action}` as "/api/v1/trees/{tree_id}/proposals/{proposal_id}/apply",
      { params: { path: { tree_id: treeId, proposal_id: pid } } },
    );
    setBusy(null);
    if (error) {
      // 409 = couldn't apply (e.g. references a missing record); reload shows apply_error.
      if (response.status !== 409) alert("Action failed.");
    }
    load();
  }

  if (!ready) return <p className="text-[var(--muted)]">Loading…</p>;

  return (
    <div className="space-y-6">
      <div>
        <h1 className="text-2xl font-semibold">Change proposals</h1>
        <p className="mt-1 text-sm text-[var(--muted)]">
          Suggested edits (from the assistant or contributors). Nothing changes until you approve —
          approving applies it as your own edit, through the normal checks and audit log.
        </p>
      </div>

      {proposals.length === 0 ? (
        <p className="text-[var(--muted)]">No proposals.</p>
      ) : (
        <ul className="space-y-3">
          {proposals.map((p) => {
            const ops = (p.operations as Op[]) ?? [];
            return (
              <li key={p.id}>
                <Card>
                  <CardContent className="space-y-3 p-5">
                    <div className="flex flex-wrap items-start justify-between gap-3">
                      <div className="min-w-0">
                        <div className="font-medium">{p.summary}</div>
                        <div className="text-xs text-[var(--muted)]">
                          {p.origin} · {ops.length} change{ops.length === 1 ? "" : "s"}
                        </div>
                      </div>
                      <span
                        className={`shrink-0 rounded-full border px-2.5 py-0.5 text-xs ${
                          STATUS_STYLE[p.status] ?? ""
                        }`}
                      >
                        {p.status}
                      </span>
                    </div>

                    {p.rationale && <p className="text-sm text-[var(--muted)]">{p.rationale}</p>}

                    <ul className="space-y-1 text-sm">
                      {ops.map((o, i) => (
                        <li key={i} className="rounded-md bg-bronze/[0.05] px-3 py-1.5">
                          <span className="font-medium capitalize">{o.op}</span>{" "}
                          <span className="text-[var(--muted)]">{o.entity_type}</span>
                          {o.payload && Object.keys(o.payload).length > 0 && (
                            <span className="text-[var(--muted)]">
                              {" "}
                              ·{" "}
                              {Object.entries(o.payload)
                                .map(([k, v]) => `${k}: ${String(v)}`)
                                .join(", ")}
                            </span>
                          )}
                        </li>
                      ))}
                    </ul>

                    {p.apply_error && (
                      <p className="rounded-md border border-red-600/40 bg-red-600/[0.06] px-3 py-2 text-sm text-red-700 dark:text-red-400">
                        Couldn’t apply: {p.apply_error}
                      </p>
                    )}

                    {p.status === "pending" && canReview && (
                      <div className="flex gap-2">
                        <Button size="sm" disabled={busy === p.id} onClick={() => act(p.id, "apply")}>
                          Approve & apply
                        </Button>
                        <Button
                          size="sm"
                          variant="outline"
                          disabled={busy === p.id}
                          onClick={() => act(p.id, "reject")}
                        >
                          Reject
                        </Button>
                      </div>
                    )}
                    {p.status === "pending" && !canReview && (
                      <p className="text-xs text-[var(--muted)]">Only an editor can approve this.</p>
                    )}
                  </CardContent>
                </Card>
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
}
