import { useState } from "react";
import { data, Form, Link, redirect, useActionData, useLoaderData } from "react-router";
import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router";
import {
  getBandArtists,
  getBandById,
  getBandLinks,
  getIpAddress,
  listArtists,
  updateBand,
} from "~/lib/db.server";
import { ARTIST_ROLES, LINK_TYPES } from "~/lib/constants";

export async function loader({ params }: LoaderFunctionArgs) {
  const band = getBandById(params.uuid!);
  if (!band) throw data("Not found", { status: 404 });
  const links = getBandLinks(band.id);
  const bandArtists = getBandArtists(band.id);
  const allArtists = listArtists();
  return { band, links, bandArtists, allArtists };
}

export async function action({ params, request }: ActionFunctionArgs) {
  const band = getBandById(params.uuid!);
  if (!band) throw data("Not found", { status: 404 });

  const fd = await request.formData();
  const name = (fd.get("name") as string).trim();
  const slug = (fd.get("slug") as string).trim();
  const area = (fd.get("area") as string).trim() || null;
  const description = (fd.get("description") as string).trim() || null;
  const status = (fd.get("status") as string) || "active";
  const message = (fd.get("message") as string).trim();
  const links: { label: string; url: string }[] = JSON.parse(
    (fd.get("links") as string) || "[]"
  );
  const artists: { id: string; role: string | null }[] = JSON.parse(
    (fd.get("artists") as string) || "[]"
  );

  const errors: Record<string, string> = {};
  if (!name) errors.name = "必須です";
  if (!slug) errors.slug = "必須です";
  if (!message) errors.message = "必須です";
  if (Object.keys(errors).length > 0) return { errors };

  try {
    updateBand(band.id, { slug, name, area, description, status, links, artists, message, ip_address: getIpAddress(request) });
  } catch (e) {
    if (e instanceof Error && e.message.includes("UNIQUE constraint failed: bands.slug")) {
      return { errors: { slug: "このslugは既に使用されています" } };
    }
    throw e;
  }
  return redirect(`/bands/of/${band.id}`);
}

function toSlug(s: string) {
  return s.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^\w぀-ヿ一-鿿＀-￯-]/g, "").replace(/^-+|-+$/g, "");
}

type PickedArtist = { id: string; name: string; roles: string[] };
type PendingRole = { type: string; custom: string };
const DEFAULT_PENDING: PendingRole = { type: ARTIST_ROLES[0], custom: "" };

export default function BandEdit() {
  const { band, links: initLinks, bandArtists: initArtists, allArtists } = useLoaderData<typeof loader>();
  const actionData = useActionData<typeof action>();
  const errors = actionData?.errors ?? {};

  const [name, setName] = useState(band.name);
  const [slug, setSlug] = useState(band.slug);
  const [slugManual, setSlugManual] = useState(true);
  const [links, setLinks] = useState(initLinks.map((l) => ({ label: l.label, url: l.url })));
  const [picked, setPicked] = useState<PickedArtist[]>(
    initArtists.map((a) => ({
      id: a.artist_id,
      name: a.artist_name,
      roles: a.role ? a.role.split(", ").filter(Boolean) : [],
    }))
  );
  const [pending, setPending] = useState<Record<string, PendingRole>>(
    Object.fromEntries(initArtists.map((a) => [a.artist_id, { ...DEFAULT_PENDING }]))
  );

  const available = allArtists.filter((a) => !picked.some((p) => p.id === a.id));

  function addRole(artistId: string) {
    const pend = pending[artistId] ?? DEFAULT_PENDING;
    const role = pend.type === "other" ? pend.custom.trim() : pend.type;
    if (!role) return;
    setPicked((prev) => prev.map((a) => a.id === artistId ? { ...a, roles: [...a.roles, role] } : a));
  }

  function removeRole(artistId: string, idx: number) {
    setPicked((prev) => prev.map((a) => a.id === artistId ? { ...a, roles: a.roles.filter((_, i) => i !== idx) } : a));
  }

  return (
    <main className="max-w-3xl mx-auto px-4 py-8">
      <div className="flex items-center gap-3 mb-6">
        <Link to={`/bands/of/${band.id}`} className="text-gray-400 hover:text-gray-200 transition-colors">←</Link>
        <h1 className="text-xl font-semibold">Edit Band</h1>
      </div>

      <Form method="post" className="space-y-5">
        <input type="hidden" name="links" value={JSON.stringify(links)} />
        <input
          type="hidden"
          name="artists"
          value={JSON.stringify(picked.map((p) => ({ id: p.id, role: p.roles.join(", ") || null })))}
        />

        <div>
          <label className="block text-sm font-medium text-gray-300 mb-1">
            バンド名 <span className="text-red-400">*</span>
          </label>
          <input
            name="name"
            value={name}
            onChange={(e) => { setName(e.target.value); if (!slugManual) setSlug(toSlug(e.target.value)); }}
            className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-gray-100 focus:outline-none focus:border-blue-500"
          />
          {errors.name && <p className="text-red-400 text-sm mt-1">{errors.name}</p>}
        </div>

        <div>
          <label className="block text-sm font-medium text-gray-300 mb-1">
            Slug <span className="text-red-400">*</span>
          </label>
          <input
            name="slug"
            value={slug}
            onChange={(e) => { setSlugManual(true); setSlug(e.target.value); }}
            className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-gray-100 focus:outline-none focus:border-blue-500 font-mono text-sm"
          />
          {errors.slug && <p className="text-red-400 text-sm mt-1">{errors.slug}</p>}
        </div>

        <div>
          <label className="block text-sm font-medium text-gray-300 mb-1">活動拠点</label>
          <input
            name="area"
            defaultValue={band.area ?? ""}
            className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-gray-100 focus:outline-none focus:border-blue-500"
          />
        </div>

        <div>
          <label className="block text-sm font-medium text-gray-300 mb-1">ステータス</label>
          <select
            name="status"
            defaultValue={band.status}
            className="bg-gray-800 border border-gray-700 rounded px-3 py-2 text-gray-100 focus:outline-none focus:border-blue-500"
          >
            <option value="active">活動中</option>
            <option value="hiatus">活動休止</option>
            <option value="disbanded">解散</option>
          </select>
        </div>

        <div>
          <label className="block text-sm font-medium text-gray-300 mb-1">説明</label>
          <textarea
            name="description"
            rows={3}
            defaultValue={band.description ?? ""}
            className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-gray-100 focus:outline-none focus:border-blue-500 resize-none"
          />
        </div>

        <div>
          <label className="block text-sm font-medium text-gray-300 mb-2">リンク</label>
          <div className="space-y-2">
            {links.map((link, i) => (
              <div key={i} className="flex gap-2">
                <select
                  value={link.label}
                  onChange={(e) => setLinks(links.map((l, idx) => idx === i ? { ...l, label: e.target.value } : l))}
                  className="w-36 bg-gray-800 border border-gray-700 rounded px-3 py-2 text-gray-100 focus:outline-none focus:border-blue-500 text-sm"
                >
                  {LINK_TYPES.map((t) => <option key={t.value} value={t.value}>{t.label}</option>)}
                </select>
                <input
                  value={link.url}
                  onChange={(e) => setLinks(links.map((l, idx) => idx === i ? { ...l, url: e.target.value } : l))}
                  placeholder="https://..."
                  className="flex-1 bg-gray-800 border border-gray-700 rounded px-3 py-2 text-gray-100 focus:outline-none focus:border-blue-500 text-sm"
                />
                <button type="button" onClick={() => setLinks(links.filter((_, idx) => idx !== i))} className="text-gray-500 hover:text-red-400 px-2 transition-colors">×</button>
              </div>
            ))}
          </div>
          <button
            type="button"
            onClick={() => setLinks([...links, { label: LINK_TYPES[0].value, url: "" }])}
            className="mt-2 text-blue-400 hover:text-blue-300 text-sm transition-colors"
          >
            + リンクを追加
          </button>
        </div>

        <div>
          <label className="block text-sm font-medium text-gray-300 mb-2">メンバー</label>
          {picked.length > 0 && (
            <div className="space-y-2 mb-3">
              {picked.map((p) => {
                const pend = pending[p.id] ?? DEFAULT_PENDING;
                return (
                  <div key={p.id} className="bg-gray-900 rounded-lg p-3">
                    <div className="flex items-center justify-between mb-2">
                      <span className="text-gray-200 text-sm font-medium">{p.name}</span>
                      <button
                        type="button"
                        onClick={() => setPicked(picked.filter((a) => a.id !== p.id))}
                        className="text-gray-500 hover:text-red-400 text-xs transition-colors"
                      >
                        削除
                      </button>
                    </div>
                    {p.roles.length > 0 && (
                      <div className="flex flex-wrap gap-1.5 mb-2">
                        {p.roles.map((r, ri) => (
                          <span key={ri} className="inline-flex items-center gap-1 bg-gray-800 text-gray-300 text-xs px-2 py-0.5 rounded">
                            {r}
                            <button type="button" onClick={() => removeRole(p.id, ri)} className="text-gray-500 hover:text-red-400 leading-none">×</button>
                          </span>
                        ))}
                      </div>
                    )}
                    <div className="flex gap-2 items-center">
                      <select
                        value={pend.type}
                        onChange={(e) => setPending({ ...pending, [p.id]: { ...pend, type: e.target.value } })}
                        className="bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-gray-300 text-sm focus:outline-none focus:border-blue-500"
                      >
                        {ARTIST_ROLES.map((r) => <option key={r} value={r}>{r}</option>)}
                        <option value="other">その他...</option>
                      </select>
                      {pend.type === "other" && (
                        <input
                          value={pend.custom}
                          onChange={(e) => setPending({ ...pending, [p.id]: { ...pend, custom: e.target.value } })}
                          placeholder="ロール名"
                          className="bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-gray-300 text-sm focus:outline-none focus:border-blue-500 w-32"
                        />
                      )}
                      <button
                        type="button"
                        onClick={() => addRole(p.id)}
                        className="text-blue-400 hover:text-blue-300 text-sm transition-colors"
                      >
                        + 追加
                      </button>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
          {available.length > 0 && (
            <select
              onChange={(e) => {
                const a = allArtists.find((x) => x.id === e.target.value);
                if (a) {
                  setPicked([...picked, { id: a.id, name: a.name, roles: [] }]);
                  setPending({ ...pending, [a.id]: { ...DEFAULT_PENDING } });
                  e.target.value = "";
                }
              }}
              defaultValue=""
              className="bg-gray-800 border border-gray-700 rounded px-3 py-2 text-gray-400 focus:outline-none focus:border-blue-500 text-sm"
            >
              <option value="">+ アーティストを追加...</option>
              {available.map((a) => <option key={a.id} value={a.id}>{a.name}</option>)}
            </select>
          )}
        </div>

        <div>
          <label className="block text-sm font-medium text-gray-300 mb-1">
            更新メッセージ <span className="text-red-400">*</span>
          </label>
          <input
            name="message"
            placeholder="例: メンバー追加"
            className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-gray-100 focus:outline-none focus:border-blue-500"
          />
          {errors.message && <p className="text-red-400 text-sm mt-1">{errors.message}</p>}
        </div>

        <div className="flex gap-3 pt-2">
          <button type="submit" className="bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded font-medium transition-colors">保存</button>
          <Link to={`/bands/of/${band.id}`} className="bg-gray-800 hover:bg-gray-700 text-gray-300 px-4 py-2 rounded transition-colors">キャンセル</Link>
        </div>
      </Form>
    </main>
  );
}
