import { useState } from "react";
import { data, Form, Link, redirect, useActionData, useLoaderData } from "react-router";
import type { ActionFunctionArgs, LoaderFunctionArgs } from "react-router";
import {
  getBandById,
  getBandLinks,
  getBandMembers,
  getIpAddress,
  listArtists,
  updateBand,
  type MemberInput,
} 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 members = getBandMembers(band.id);
  const allArtists = listArtists();
  return { band, links, members, 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 members: MemberInput[] = JSON.parse((fd.get("members") 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, members, 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 MemberEntry = {
  key: string;
  artist_id: string;
  artist_name: string;
  roles: string[];
  since: string;
  until: string;
  note: string;
  pendingRole: { type: string; custom: string };
};

const DEFAULT_PENDING = { type: ARTIST_ROLES[0], custom: "" };

export default function BandEdit() {
  const { band, links: initLinks, members: initMembers, 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 [entries, setEntries] = useState<MemberEntry[]>(
    initMembers.map((m) => ({
      key: crypto.randomUUID(),
      artist_id: m.artist_id,
      artist_name: m.artist_name,
      roles: m.role ? m.role.split(", ").filter(Boolean) : [],
      since: m.since,
      until: m.until,
      note: m.note,
      pendingRole: { ...DEFAULT_PENDING },
    }))
  );

  const usedArtistIds = new Set(entries.map((e) => e.artist_id));
  const available = allArtists.filter((a) => !usedArtistIds.has(a.id));
  const artistIds = [...new Set(entries.map((e) => e.artist_id))];

  function addArtist(artistId: string) {
    const a = allArtists.find((x) => x.id === artistId);
    if (!a) return;
    setEntries((prev) => [
      ...prev,
      { key: crypto.randomUUID(), artist_id: a.id, artist_name: a.name, roles: [], since: "", until: "", note: "", pendingRole: { ...DEFAULT_PENDING } },
    ]);
  }

  function addPeriod(artistId: string) {
    const ref = entries.find((e) => e.artist_id === artistId);
    if (!ref) return;
    setEntries((prev) => [
      ...prev,
      { key: crypto.randomUUID(), artist_id: ref.artist_id, artist_name: ref.artist_name, roles: [], since: "", until: "", note: "", pendingRole: { ...DEFAULT_PENDING } },
    ]);
  }

  function removeArtist(artistId: string) {
    setEntries((prev) => prev.filter((e) => e.artist_id !== artistId));
  }

  function removeEntry(key: string) {
    setEntries((prev) => prev.filter((e) => e.key !== key));
  }

  function updateEntry<K extends keyof MemberEntry>(key: string, field: K, value: MemberEntry[K]) {
    setEntries((prev) => prev.map((e) => e.key === key ? { ...e, [field]: value } : e));
  }

  function addRole(key: string) {
    const entry = entries.find((e) => e.key === key);
    if (!entry) return;
    const role = entry.pendingRole.type === "other" ? entry.pendingRole.custom.trim() : entry.pendingRole.type;
    if (!role) return;
    setEntries((prev) => prev.map((e) => e.key === key ? { ...e, roles: [...e.roles, role] } : e));
  }

  function removeRole(key: string, idx: number) {
    setEntries((prev) => prev.map((e) => e.key === key ? { ...e, roles: e.roles.filter((_, i) => i !== idx) } : e));
  }

  const serialized: MemberInput[] = entries.map((e) => ({
    artist_id: e.artist_id,
    role: e.roles.join(", ") || null,
    since: e.since,
    until: e.until,
    note: e.note,
  }));

  return (
    <main>
      <div className="page-header">
        <Link to={`/bands/of/${band.id}`} className="back">←</Link>
        <h1>Edit Band</h1>
      </div>

      <Form method="post">
        <input type="hidden" name="links" value={JSON.stringify(links)} />
        <input type="hidden" name="members" value={JSON.stringify(serialized)} />

        <div>
          <label>バンド名 <span className="req">*</span></label>
          <input
            name="name"
            value={name}
            onChange={(e) => { setName(e.target.value); if (!slugManual) setSlug(toSlug(e.target.value)); }}
          />
          {errors.name && <p className="error">{errors.name}</p>}
        </div>

        <div>
          <label>Slug <span className="req">*</span></label>
          <input
            name="slug"
            value={slug}
            onChange={(e) => { setSlugManual(true); setSlug(e.target.value); }}
            className="mono"
          />
          {errors.slug && <p className="error">{errors.slug}</p>}
        </div>

        <div>
          <label>活動拠点</label>
          <input name="area" defaultValue={band.area ?? ""} />
        </div>

        <div>
          <label>ステータス</label>
          <select name="status" defaultValue={band.status}>
            <option value="active">活動中</option>
            <option value="hiatus">活動休止</option>
            <option value="disbanded">解散</option>
          </select>
        </div>

        <div>
          <label>説明</label>
          <textarea name="description" rows={3} defaultValue={band.description ?? ""} />
        </div>

        <div>
          <label>リンク</label>
          <div className="links-form">
            {links.map((link, i) => (
              <div key={i} className="link-row">
                <select
                  value={link.label}
                  onChange={(e) => setLinks(links.map((l, idx) => idx === i ? { ...l, label: e.target.value } : l))}
                >
                  {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://..."
                />
                <button type="button" className="btn-icon" onClick={() => setLinks(links.filter((_, idx) => idx !== i))}>×</button>
              </div>
            ))}
          </div>
          <button type="button" className="btn-text" onClick={() => setLinks([...links, { label: LINK_TYPES[0].value, url: "" }])}>
            + リンクを追加
          </button>
        </div>

        <div>
          <label>メンバー</label>
          {artistIds.length > 0 && (
            <div className="members-form">
              {artistIds.map((artistId) => {
                const group = entries.filter((e) => e.artist_id === artistId);
                return (
                  <div key={artistId} className="member-group">
                    <div className="card-header">
                      <span className="card-name">{group[0].artist_name}</span>
                      <button type="button" className="btn-text" onClick={() => addPeriod(artistId)}>+ 期間追加</button>
                      <button type="button" className="btn-icon" onClick={() => removeArtist(artistId)}>削除</button>
                    </div>
                    {group.map((entry) => (
                      <div key={entry.key} className="member-card">
                        {group.length > 1 && (
                          <div style={{ textAlign: "right" }}>
                            <button type="button" className="btn-icon" onClick={() => removeEntry(entry.key)}>×</button>
                          </div>
                        )}
                        {entry.roles.length > 0 && (
                          <div className="badges">
                            {entry.roles.map((r, ri) => (
                              <span key={ri} className="badge">
                                {r}
                                <button type="button" onClick={() => removeRole(entry.key, ri)}>×</button>
                              </span>
                            ))}
                          </div>
                        )}
                        <div className="role-row">
                          <select
                            value={entry.pendingRole.type}
                            onChange={(e) => updateEntry(entry.key, "pendingRole", { ...entry.pendingRole, type: e.target.value })}
                          >
                            {ARTIST_ROLES.map((r) => <option key={r} value={r}>{r}</option>)}
                            <option value="other">その他...</option>
                          </select>
                          {entry.pendingRole.type === "other" && (
                            <input
                              className="custom-input"
                              value={entry.pendingRole.custom}
                              onChange={(e) => updateEntry(entry.key, "pendingRole", { ...entry.pendingRole, custom: e.target.value })}
                              placeholder="ロール名"
                            />
                          )}
                          <button type="button" className="btn-text" onClick={() => addRole(entry.key)}>+ 追加</button>
                        </div>
                        <div className="period-row">
                          <input
                            type="month"
                            value={entry.since}
                            onChange={(e) => updateEntry(entry.key, "since", e.target.value)}
                          />
                          <span className="period-sep">〜</span>
                          <input
                            type="month"
                            value={entry.until}
                            onChange={(e) => updateEntry(entry.key, "until", e.target.value)}
                          />
                          <input
                            className="period-note"
                            value={entry.note}
                            onChange={(e) => updateEntry(entry.key, "note", e.target.value)}
                            placeholder="ノート"
                          />
                        </div>
                      </div>
                    ))}
                  </div>
                );
              })}
            </div>
          )}
          {available.length > 0 && (
            <select
              onChange={(e) => { if (e.target.value) { addArtist(e.target.value); e.target.value = ""; } }}
              defaultValue=""
            >
              <option value="">+ アーティストを追加...</option>
              {available.map((a) => <option key={a.id} value={a.id}>{a.name}</option>)}
            </select>
          )}
        </div>

        <div>
          <label>更新メッセージ <span className="req">*</span></label>
          <input name="message" placeholder="例: メンバー追加" />
          {errors.message && <p className="error">{errors.message}</p>}
        </div>

        <div className="actions">
          <button type="submit">保存</button>
          <Link to={`/bands/of/${band.id}`} className="btn">キャンセル</Link>
        </div>
      </Form>
    </main>
  );
}
