"use client";

import { useState } from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { Button } from "@/app/shadcn_components/ui/button";
import { Input } from "@/app/shadcn_components/ui/input";
import { Pencil, Trash2, Check, X, Plus } from "lucide-react";
import { MAX_TAG_NAME_LENGTH } from "@/lib/tags/model";
import { TagChip } from "@/app/portfolio/[slug]/components/TagChip";
import {
  Tag,
  usePortfolioTags,
  portfolioTagsKey,
} from "@/app/portfolio/[slug]/components/useTags";

const DEFAULT_COLOUR = "#6366f1";

export default function TagsCard({ portfolioId }: { portfolioId: string }) {
  const queryClient = useQueryClient();
  const { data: tags = [], isLoading } = usePortfolioTags(portfolioId);

  const [name, setName] = useState("");
  const [colour, setColour] = useState(DEFAULT_COLOUR);
  const [formError, setFormError] = useState<string | null>(null);
  const [editingId, setEditingId] = useState<string | null>(null);

  const invalidate = () =>
    queryClient.invalidateQueries({ queryKey: portfolioTagsKey(portfolioId) });

  const createTag = useMutation({
    mutationFn: async (input: { name: string; colour: string }) => {
      const res = await fetch(`/api/portfolio/${portfolioId}/tags`, {
        method: "POST",
        body: JSON.stringify(input),
      });
      const body = await res.json();
      if (!res.ok) throw new Error(body.error ?? "Failed to create tag");
      return body;
    },
    onSuccess: () => {
      setName("");
      setColour(DEFAULT_COLOUR);
      setFormError(null);
      invalidate();
    },
    onError: (e: Error) => setFormError(e.message),
  });

  return (
    <div className="max-w-2xl">
      <h2 className="text-lg font-semibold mb-1">Tags</h2>
      <p className="text-sm text-gray-500 mb-5">
        Group properties to run scenarios on a subset or filter your reporting.
        Assign tags from the property table.
      </p>

      {/* Create */}
      <form
        className="flex items-end gap-2 mb-6"
        onSubmit={(e) => {
          e.preventDefault();
          createTag.mutate({ name, colour });
        }}
      >
        <label className="flex flex-col gap-1">
          <span className="text-xs font-medium text-gray-500">Colour</span>
          <input
            type="color"
            value={colour}
            onChange={(e) => setColour(e.target.value)}
            className="h-9 w-10 rounded-md border border-gray-300 bg-white p-0.5 cursor-pointer"
            aria-label="Tag colour"
          />
        </label>
        <label className="flex flex-col gap-1 flex-1">
          <span className="text-xs font-medium text-gray-500">Name</span>
          <Input
            value={name}
            maxLength={MAX_TAG_NAME_LENGTH}
            onChange={(e) => setName(e.target.value)}
            placeholder="e.g. Void, Phase 1, Exclude from report"
          />
        </label>
        <Button type="submit" disabled={!name.trim() || createTag.isLoading}>
          <Plus className="h-4 w-4 mr-1" />
          Add tag
        </Button>
      </form>
      {formError && <p className="text-sm text-red-600 -mt-4 mb-4">{formError}</p>}

      {/* List */}
      {isLoading ? (
        <p className="text-sm text-gray-400">Loading…</p>
      ) : tags.length === 0 ? (
        <p className="text-sm text-gray-400">No tags yet.</p>
      ) : (
        <ul className="divide-y divide-gray-100 border border-gray-200 rounded-lg">
          {tags.map((tag) =>
            editingId === tag.id ? (
              <EditRow
                key={tag.id}
                portfolioId={portfolioId}
                tag={tag}
                onDone={() => {
                  setEditingId(null);
                  invalidate();
                }}
                onCancel={() => setEditingId(null)}
              />
            ) : (
              <TagRow
                key={tag.id}
                portfolioId={portfolioId}
                tag={tag}
                onEdit={() => setEditingId(tag.id)}
                onDeleted={invalidate}
              />
            ),
          )}
        </ul>
      )}
    </div>
  );
}

function TagRow({
  portfolioId,
  tag,
  onEdit,
  onDeleted,
}: {
  portfolioId: string;
  tag: Tag;
  onEdit: () => void;
  onDeleted: () => void;
}) {
  const del = useMutation({
    mutationFn: async () => {
      const res = await fetch(`/api/portfolio/${portfolioId}/tags/${tag.id}`, {
        method: "DELETE",
      });
      if (!res.ok) throw new Error("Failed to delete tag");
    },
    onSuccess: onDeleted,
  });

  return (
    <li className="flex items-center gap-3 px-3 py-2.5">
      <TagChip colour={tag.colour} name={tag.name} />
      <span className="text-xs text-gray-400">
        {tag.propertyCount} propert{tag.propertyCount === 1 ? "y" : "ies"}
      </span>
      <div className="ml-auto flex items-center gap-1">
        <Button variant="ghost" size="sm" onClick={onEdit} title="Edit">
          <Pencil className="h-3.5 w-3.5" />
        </Button>
        <Button
          variant="ghost"
          size="sm"
          disabled={del.isLoading}
          title="Delete"
          onClick={() => {
            if (
              confirm(
                `Delete "${tag.name}"? This removes it from ${tag.propertyCount} propert${tag.propertyCount === 1 ? "y" : "ies"}.`,
              )
            ) {
              del.mutate();
            }
          }}
        >
          <Trash2 className="h-3.5 w-3.5 text-red-500" />
        </Button>
      </div>
    </li>
  );
}

function EditRow({
  portfolioId,
  tag,
  onDone,
  onCancel,
}: {
  portfolioId: string;
  tag: Tag;
  onDone: () => void;
  onCancel: () => void;
}) {
  const [name, setName] = useState(tag.name);
  const [colour, setColour] = useState(tag.colour);
  const [error, setError] = useState<string | null>(null);

  const save = useMutation({
    mutationFn: async () => {
      const res = await fetch(`/api/portfolio/${portfolioId}/tags/${tag.id}`, {
        method: "PATCH",
        body: JSON.stringify({ name, colour }),
      });
      const body = await res.json();
      if (!res.ok) throw new Error(body.error ?? "Failed to save");
      return body;
    },
    onSuccess: onDone,
    onError: (e: Error) => setError(e.message),
  });

  return (
    <li className="flex items-center gap-2 px-3 py-2.5 bg-gray-50">
      <input
        type="color"
        value={colour}
        onChange={(e) => setColour(e.target.value)}
        className="h-8 w-9 rounded-md border border-gray-300 bg-white p-0.5 cursor-pointer"
        aria-label="Tag colour"
      />
      <Input
        value={name}
        maxLength={MAX_TAG_NAME_LENGTH}
        onChange={(e) => setName(e.target.value)}
        className="flex-1"
      />
      {error && <span className="text-xs text-red-600">{error}</span>}
      <Button
        size="sm"
        disabled={!name.trim() || save.isLoading}
        onClick={() => save.mutate()}
        title="Save"
      >
        <Check className="h-3.5 w-3.5" />
      </Button>
      <Button variant="ghost" size="sm" onClick={onCancel} title="Cancel">
        <X className="h-3.5 w-3.5" />
      </Button>
    </li>
  );
}
