"use client";

import { fetchOnce } from "@/lib/fetch-once";

import { useEffect, useState } from "react";
import {
  User as UserIcon, Lock, BadgeCheck, Ban, Crown, Smartphone, MapPin,
  Trash2, Check, Loader2, Upload, Apple, Play, FileText, Clock, Palette, Ticket } from "lucide-react";
import type { PublicProfile } from "@/lib/types";
import { fileToDataUrl } from "@/lib/image";
import { sfx } from "@/lib/sfx";
import { AddressMap } from "./AddressMap";
import clsx from "clsx";

type Section =
  | "account"
  | "away"
  | "about"
  | "profile"
  | "verification"
  | "invitations"
  | "blocking"
  | "membership"
  | "app"
  | "address"
  | "delete";

const MENU: { id: Section; label: string; icon: typeof UserIcon }[] = [
  { id: "account", label: "Account", icon: Lock },
  { id: "profile", label: "Edit profile", icon: UserIcon },
  { id: "about", label: "About me", icon: FileText },
  { id: "verification", label: "Verification", icon: BadgeCheck },
  { id: "invitations", label: "Invitations", icon: Ticket },
  { id: "away", label: "Away message", icon: Clock },
  { id: "blocking", label: "Blocking", icon: Ban },
  { id: "membership", label: "Membership", icon: Crown },
  { id: "app", label: "Mobile app", icon: Smartphone },
  { id: "address", label: "Your addresses", icon: MapPin },
  { id: "delete", label: "Delete account", icon: Trash2 },
];

/** Settings, split into a left menu and a form on the right. */
export function ProfileSettings({
  profile,
  onSaved,
}: {
  profile: PublicProfile;
  onSaved: () => void;
}) {
  const [section, setSection] = useState<Section>("account");
  const [saving, setSaving] = useState(false);
  const [note, setNote] = useState<string | null>(null);

  // Account
  const [email, setEmail] = useState(profile.email ?? "");
  const [currentPassword, setCurrentPassword] = useState("");
  const [newPassword, setNewPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");

  // Profile details
  const [name, setName] = useState(profile.name ?? "");
  const [surname, setSurname] = useState(profile.surname ?? "");
  const [sex, setSex] = useState(profile.sex ?? "");
  const [relationship, setRelationship] = useState(profile.relationship ?? "");
  const [country, setCountry] = useState(profile.country ?? "");
  const [city, setCity] = useState(profile.location ?? "");
  const [birthday, setBirthday] = useState(profile.birthday ?? "");
  const [about, setAbout] = useState(profile.bio ?? "");

  // Verification
  const [idPhoto, setIdPhoto] = useState<string | null>(null);
  const [holdingPhoto, setHoldingPhoto] = useState<string | null>(null);
  const [extraInfo, setExtraInfo] = useState("");

  // Addresses
  const [themes, setThemes] = useState<
    {
      id: string; name: string; description: string; price: number;
      owned: boolean; active: boolean;
      preview: { bg: string; card: string; accent: string; text: string };
      tokens: Record<string, string>;
    }[]
  >([]);

  useEffect(() => {
    fetchOnce<Record<string, unknown>>("/api/themes")
      .then((d) => d)
      .then((d) => setThemes(Array.isArray(d) ? d : []))
      .catch(() => {});
  }, []);

  /** Buying and switching are the same action — the server charges only once. */
  async function chooseTheme(t: { id: string; name: string; price: number; owned: boolean }) {
    if (!t.owned && !confirm(`Buy the ${t.name} theme for $${t.price}?`)) return;

    const res = await fetch("/api/themes", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ themeId: t.id }),
    }).catch(() => null);

    const d = res ? await res.json() : null;
    if (!res || !res.ok) return flash(d?.error ?? "Couldn't apply that theme");

    // Apply straight away rather than making them reload.
    const root = document.documentElement;
    for (const prop of Array.from(root.style)) {
      if (prop.startsWith("--theme-")) root.style.removeProperty(prop);
    }
    for (const [k, v] of Object.entries(d.tokens ?? {})) {
      root.style.setProperty(k, String(v));
    }

    setThemes((all) => all.map((x) => ({ ...x, active: x.id === t.id, owned: x.owned || x.id === t.id })));
    flash(d.bought ? `${t.name} is yours` : `Switched to ${t.name}`);
  }

  const [awayMessage, setAwayMessage] = useState(profile.awayMessage ?? "");
  const [awayUntil, setAwayUntil] = useState(
    profile.awayUntil ? profile.awayUntil.slice(0, 10) : ""
  );
  const [addressLine, setAddressLine] = useState("");
  const [addresses, setAddresses] = useState<string[]>(profile.addresses ?? []);
  const [mapOpen, setMapOpen] = useState(false);
  const [stores, setStores] = useState({ ios: "", android: "" });

  useEffect(() => {
    fetchOnce<Record<string, unknown>>("/api/settings")
      .then((d) => d)
      .then((d) => d?.appLinks && setStores(d.appLinks as { ios: string; android: string }))
      .catch(() => {});
  }, []);

  function flash(msg: string) {
    setNote(msg);
    sfx.save();
    setTimeout(() => setNote(null), 2400);
  }

  async function save(body: Record<string, unknown>, msg: string) {
    setSaving(true);
    const res = await fetch("/api/me", {
      method: "PATCH",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    }).catch(() => null);
    setSaving(false);
    if (!res || !res.ok) {
      setNote("Couldn't save — please try again.");
      setTimeout(() => setNote(null), 2400);
      return;
    }
    flash(msg);
    onSaved();
  }

  async function pickPhoto(set: (v: string) => void) {
    const input = document.createElement("input");
    input.type = "file";
    input.accept = "image/*";
    // Some browsers ignore .click() on an input that isn't in the document,
    // which is why the verification photo pickers never opened.
    input.style.display = "none";
    document.body.appendChild(input);

    input.onchange = async () => {
      const f = input.files?.[0];
      input.remove();
      if (!f) return;

      // Uploaded rather than inlined — a pair of base64 photos in the user
      // record bloats the database.
      const form = new FormData();
      form.append("file", f);
      const res = await fetch("/api/upload", { method: "POST", body: form }).catch(() => null);
      const data = res && res.ok ? await res.json().catch(() => null) : null;

      if (data?.url) {
        set(data.url);
        return;
      }
      // If the upload fails, fall back so the person isn't stuck.
      const url = await fileToDataUrl(f, 1200).catch(() => null);
      if (url) set(url);
    };

    input.click();
  }

  return (
    <div className="ps-wrap">
      <nav className="ps-menu">
        {MENU.map((m) => (
          <button
            key={m.id}
            onClick={() => setSection(m.id)}
            className={clsx("ps-menuitem", section === m.id && "on", m.id === "delete" && "danger")}
          >
            <m.icon size={16} /> {m.label}
          </button>
        ))}
      </nav>

      <div className="ps-panel">
        {section === "account" && (
          <>
            <h3>Account settings</h3>
            <p className="ps-hint">Your sign-in details. Leave the password fields empty to keep your current one.</p>

            <label className="ps-field">
              <span>Email address</span>
              <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@example.com" />
            </label>
            <label className="ps-field">
              <span>Current password</span>
              <input type="password" value={currentPassword} onChange={(e) => setCurrentPassword(e.target.value)} />
            </label>
            <div className="ps-row">
              <label className="ps-field">
                <span>New password</span>
                <input type="password" value={newPassword} onChange={(e) => setNewPassword(e.target.value)} />
              </label>
              <label className="ps-field">
                <span>Confirm new password</span>
                <input type="password" value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} />
              </label>
            </div>

            <button
              onClick={() => {
                if (newPassword && newPassword !== confirmPassword) {
                  setNote("The new passwords don't match.");
                  setTimeout(() => setNote(null), 2400);
                  return;
                }
                save(
                  { email, currentPassword, newPassword: newPassword || undefined },
                  "Account updated"
                );
              }}
              disabled={saving}
              className="ps-save"
            >
              {saving ? <Loader2 size={15} className="animate-spin" /> : <Check size={15} />}
              Save changes
            </button>
          </>
        )}

        {section === "profile" && (
          <>
            <h3>Edit profile</h3>
            <p className="ps-hint">This is what other people see on your profile.</p>

            <div className="ps-row">
              <label className="ps-field">
                <span>First name</span>
                <input value={name} onChange={(e) => setName(e.target.value)} />
              </label>
              <label className="ps-field">
                <span>Surname</span>
                <input
                  value={surname}
                  onChange={(e) => setSurname(e.target.value.slice(0, 20))}
                  maxLength={20}
                  placeholder="Up to 20 characters"
                />
              </label>
            </div>

            <div className="ps-row">
              <label className="ps-field">
                <span>Sex</span>
                <select value={sex} onChange={(e) => setSex(e.target.value)}>
                  <option value="">Prefer not to say</option>
                  <option value="male">Male</option>
                  <option value="female">Female</option>
                </select>
              </label>
              <label className="ps-field">
                <span>Relationship</span>
                <select value={relationship} onChange={(e) => setRelationship(e.target.value)}>
                  <option value="">Prefer not to say</option>
                  <option>Single</option>
                  <option>In a relationship</option>
                  <option>Engaged</option>
                  <option>Married</option>
                  <option>It&apos;s complicated</option>
                </select>
              </label>
            </div>

            <div className="ps-row">
              <label className="ps-field">
                <span>Country</span>
                <input value={country} onChange={(e) => setCountry(e.target.value)} placeholder="United Kingdom" />
              </label>
              <label className="ps-field">
                <span>City</span>
                <input value={city} onChange={(e) => setCity(e.target.value)} placeholder="Southend-on-Sea" />
              </label>
            </div>

            <label className="ps-field">
              <span>Birthday</span>
              <input type="date" value={birthday} onChange={(e) => setBirthday(e.target.value)} />
            </label>


            <button
              onClick={() =>
                save(
                  { name, surname, sex, relationship, country, location: city, birthday, bio: about },
                  "Profile updated"
                )
              }
              disabled={saving}
              className="ps-save"
            >
              {saving ? <Loader2 size={15} className="animate-spin" /> : <Check size={15} />}
              Save changes
            </button>
          </>
        )}

        {section === "about" && (
          <>
            <h3>About me</h3>
            <p className="ps-hint">
              A short introduction shown on your profile. Say what you do, what
              you&apos;re into, or why people should follow you.
            </p>

            <div className="ps-about">
              <textarea
                value={about}
                onChange={(e) => setAbout(e.target.value.slice(0, 300))}
                rows={6}
                placeholder="I design interfaces, take too many photos of my dog, and sell the occasional camera lens..."
              />
              <span className={clsx("ps-count", about.length > 260 && "near")}>
                {about.length}/300
              </span>
            </div>

            <div className="ps-preview">
              <p className="ps-previewlabel">How it looks on your profile</p>
              <div className="ps-previewcard">
                {about.trim() ? about : "Nothing here yet."}
              </div>
            </div>

            <button onClick={() => save({ bio: about }, "About updated")} disabled={saving} className="ps-save">
              {saving ? <Loader2 size={15} className="animate-spin" /> : <Check size={15} />}
              Save
            </button>
          </>
        )}

        {section === "invitations" && <Invitations />}

        {section === "verification" && (
          <>
            <h3>Verification</h3>
            <p className="ps-hint">
              Verified accounts get a badge on their profile. Send a photo of your
              ID and a photo of yourself holding it — both are reviewed by a
              person and never shown publicly.
            </p>

            <div className="ps-row">
              <button onClick={() => pickPhoto(setIdPhoto)} className="ps-upload">
                {idPhoto ? (
                  // eslint-disable-next-line @next/next/no-img-element
                  <img src={idPhoto} alt="" />
                ) : (
                  <>
                    <Upload size={20} />
                    <b>Photo ID</b>
                    <em>Passport or driving licence</em>
                  </>
                )}
              </button>
              <button onClick={() => pickPhoto(setHoldingPhoto)} className="ps-upload">
                {holdingPhoto ? (
                  // eslint-disable-next-line @next/next/no-img-element
                  <img src={holdingPhoto} alt="" />
                ) : (
                  <>
                    <Upload size={20} />
                    <b>You holding it</b>
                    <em>Face and ID both visible</em>
                  </>
                )}
              </button>
            </div>

            <label className="ps-field">
              <span>Additional information</span>
              <textarea rows={3} value={extraInfo} onChange={(e) => setExtraInfo(e.target.value.slice(0, 400))} placeholder="Anything that helps us confirm who you are" />
            </label>

            <button
              onClick={() =>
                save({ verification: { idPhoto, holdingPhoto, extraInfo } }, "Sent for review")
              }
              disabled={saving || !idPhoto || !holdingPhoto}
              className={clsx("ps-save", (!idPhoto || !holdingPhoto) && "off")}
            >
              Submit for review
            </button>
          </>
        )}

        {section === "away" && (
          <>
            <h3>Away message</h3>
            <p className="ps-hint">
              Sent automatically the first time someone messages you while
              this is on. They only get it once per conversation.
            </p>

            <label className="ps-field">
              <span>Message</span>
              <textarea
                rows={3}
                value={awayMessage}
                onChange={(e) => setAwayMessage(e.target.value.slice(0, 200))}
                placeholder="Away until Monday — I'll reply then."
              />
            </label>

            <label className="ps-field">
              <span>Turn off automatically on (optional)</span>
              <input
                type="date"
                value={awayUntil}
                onChange={(e) => setAwayUntil(e.target.value)}
              />
            </label>

            <div className="ps-row">
              <button
                onClick={() => save({ awayMessage, awayUntil }, "Away message on")}
                disabled={saving || !awayMessage.trim()}
                className="ps-save"
              >
                {saving ? <Loader2 size={15} className="animate-spin" /> : <Check size={15} />}
                Turn on
              </button>
              <button
                onClick={() => {
                  setAwayMessage("");
                  setAwayUntil("");
                  save({ awayMessage: "", awayUntil: "" }, "Away message off");
                }}
                className="ps-cancelaway"
              >
                Turn off
              </button>
            </div>
          </>
        )}

        {section === "blocking" && (
          <>
            <h3>Blocking</h3>
            <p className="ps-hint">People you&apos;ve blocked can&apos;t message you, see your posts or find your profile.</p>
            <BlockedList />
          </>
        )}

        {section === "membership" && (
          <>
            <h3>Membership</h3>
            <div className="ps-plan current">
              <span>
                <b>{profile.premium ? "Premium" : "Free"}</b>
                <em>{profile.premium ? "Thanks for supporting XRcoin." : "The standard account."}</em>
              </span>
              <i>Current</i>
            </div>

            {!profile.premium && (
              <div className="ps-plan">
                <span>
                  <b>Premium — $5/month</b>
                  <em>No ads, a profile frame, higher upload limits and priority support.</em>
                </span>
                <button onClick={() => save({ upgrade: true }, "Welcome to Premium")} className="ps-upgrade">
                  Upgrade
                </button>
              </div>
            )}
          </>
        )}

        {section === "app" && (
          <>
            <h3>Mobile app</h3>
            <p className="ps-hint">Take XRcoin with you. Same account, same everything.</p>
            <div className="ps-row">
              <a
                href={stores.ios || undefined}
                target="_blank"
                rel="noreferrer"
                className={clsx("ps-store", !stores.ios && "soon")}
              >
                <Apple size={22} />
                <span>
                  <em>{stores.ios ? "Download on the" : "Not yet on the"}</em>
                  <b>App Store</b>
                </span>
              </a>
              <a
                href={stores.android || undefined}
                target="_blank"
                rel="noreferrer"
                className={clsx("ps-store", !stores.android && "soon")}
              >
                <Play size={22} />
                <span>
                  <em>{stores.android ? "Get it on" : "Not yet on"}</em>
                  <b>Google Play</b>
                </span>
              </a>
            </div>
          </>
        )}

        {section === "address" && (
          <>
            <h3>Your addresses</h3>
            <p className="ps-hint">Saved addresses make checkout and delivery quicker.</p>

            <button onClick={() => setMapOpen(true)} className="ps-mapbtn">
              <MapPin size={16} /> Pick on a map
            </button>

            {addressLine && (
              <div className="ps-picked">
                <MapPin size={15} />
                <span className="flex-1 min-w-0">{addressLine}</span>
              </div>
            )}

            <button
              disabled={!addressLine.trim()}
              onClick={() => {
                if (!addressLine.trim()) return;
                const next = [...addresses, addressLine.trim()];
                setAddresses(next);
                setAddressLine("");
                save({ addresses: next }, "Address saved");
              }}
              className="ps-save"
            >
              Add address
            </button>

            {addresses.length > 0 && (
              <div className="ps-addrlist">
                {addresses.map((a, i) => (
                  <div key={i} className="ps-addrrow">
                    <MapPin size={14} />
                    <span className="flex-1 min-w-0">{a}</span>
                    <button
                      onClick={() => {
                        const next = addresses.filter((_, j) => j !== i);
                        setAddresses(next);
                        save({ addresses: next }, "Address removed");
                      }}
                    >
                      <Trash2 size={13} />
                    </button>
                  </div>
                ))}
              </div>
            )}
          </>
        )}

        {section === "delete" && (
          <>
            <h3>Delete account</h3>
            <p className="ps-hint">
              This removes your profile, posts, listings and messages. It can&apos;t
              be undone, and your username becomes available to others.
            </p>
            <button
              onClick={() => {
                if (
                  confirm("Delete your account permanently? This can't be undone.")
                ) {
                  save({ deleteAccount: true }, "Account scheduled for deletion");
                }
              }}
              className="ps-delete"
            >
              <Trash2 size={15} /> Delete my account
            </button>
          </>
        )}
      </div>

      {mapOpen && (
        <AddressMap
          onClose={() => setMapOpen(false)}
          onPick={(label) => {
            setAddressLine(label);
            setMapOpen(false);
          }}
        />
      )}

      {note && <div className="ps-note">{note}</div>}
    </div>
  );
}

/** People this account has blocked, with a way to undo it. */
function BlockedList() {
  const [blocked, setBlocked] = useState<
    { id: string; name: string; username: string }[] | null
  >(null);

  useState(() => {
    fetch("/api/me/blocked")
      .then((r) => (r.ok ? r.json() : []))
      .then((d) => setBlocked(Array.isArray(d) ? d : []))
      .catch(() => setBlocked([]));
  });

  if (blocked === null) return <p className="ps-hint">Loading…</p>;
  if (blocked.length === 0) return <p className="ps-hint">You haven&apos;t blocked anyone.</p>;

  return (
    <div className="ps-addrlist">
      {blocked.map((p) => (
        <div key={p.id} className="ps-addrrow">
          <span className="flex-1 min-w-0">
            <b>{p.name}</b> <em>@{p.username}</em>
          </span>
          <button
            onClick={async () => {
              await fetch(`/api/users/${p.username}/block`, { method: "POST" }).catch(() => {});
              setBlocked((l) => l?.filter((x) => x.id !== p.id) ?? null);
            }}
          >
            Unblock
          </button>
        </div>
      ))}
    </div>
  );
}


/** Invitation codes, when the site runs on invitation only. */
function Invitations() {
  const [state, setState] = useState<{
    enabled: boolean;
    allowance: number;
    remaining: number;
    invitations: { code: string; used: boolean; expired: boolean; expiresAt: string }[];
  } | null>(null);
  const [busy, setBusy] = useState(false);
  const [copied, setCopied] = useState<string | null>(null);

  const load = () =>
    fetch("/api/invitations")
      .then((r) => (r.ok ? r.json() : null))
      .then(setState)
      .catch(() => {});

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

  if (!state) return <p className="ps-hint">Loading…</p>;

  if (!state.enabled) {
    return (
      <>
        <h3>Invitations</h3>
        <p className="ps-hint">
          This site doesn&apos;t use invitations, so there&apos;s nothing to
          hand out.
        </p>
      </>
    );
  }

  return (
    <>
      <h3>Invitations</h3>
      <p className="ps-hint">
        {state.remaining} of {state.allowance} left. Each code works once.
      </p>

      <button
        onClick={async () => {
          setBusy(true);
          await fetch("/api/invitations", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({}),
          }).catch(() => {});
          setBusy(false);
          load();
        }}
        disabled={busy || state.remaining <= 0}
        className="ps-save"
      >
        {busy ? <Loader2 size={15} className="animate-spin" /> : <Ticket size={15} />}
        Create an invitation
      </button>

      {state.invitations.length > 0 && (
        <div className="as-words" style={{ marginTop: 18 }}>
          {state.invitations.map((i) => (
            <button
              key={i.code}
              onClick={() => {
                navigator.clipboard?.writeText(i.code);
                setCopied(i.code);
                setTimeout(() => setCopied(null), 1600);
              }}
              className={clsx("as-word", (i.used || i.expired) && "spent")}
              title={i.used ? "Already used" : i.expired ? "Expired" : "Copy"}
            >
              {copied === i.code ? "Copied" : i.code}
            </button>
          ))}
        </div>
      )}
    </>
  );
}
