"use client";

import { useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { useTranslations } from "next-intl";
import { useLocale, SUPPORTED_LOCALES, type Locale } from "@/lib/i18n/provider";
import { FlagGB, FlagFR } from "@/components/shared/flag-icons";
import { AvatarUploader } from "./avatar-uploader";

const LOCALE_FLAGS: Record<Locale, typeof FlagGB> = { en: FlagGB, fr: FlagFR };

const USERNAME_PATTERN = /^[a-z0-9_]{3,20}$/;

type UserProps = {
  name: string;
  email: string;
  image: string | null;
  locale: string;
  bio: string | null;
  privateBio: string | null;
  isPrivate: boolean;
  hasCustomAvatar: boolean;
  username: string | null;
  useGravatar: boolean;
};

export function SettingsForm({ user }: { user: UserProps }) {
  const t = useTranslations("settingsForm");
  const t_common = useTranslations("common");
  const { setLocale } = useLocale();

  const [avatarImage, setAvatarImage] = useState(user.image);
  const [hasCustomAvatar, setHasCustomAvatar] = useState(user.hasCustomAvatar);
  const [name, setName] = useState(user.name);
  const [bio, setBio] = useState(user.bio ?? "");
  const [privateBio, setPrivateBio] = useState(user.privateBio ?? "");
  const [saving, setSaving] = useState(false);
  const [savingBio, setSavingBio] = useState(false);
  const [isPrivate, setIsPrivate] = useState(user.isPrivate);
  const [savingPrivacy, setSavingPrivacy] = useState(false);
  const [username, setUsername] = useState(user.username ?? "");
  const [savingUsername, setSavingUsername] = useState(false);
  const [usernameError, setUsernameError] = useState<string | null>(null);
  const [useGravatar, setUseGravatar] = useState(user.useGravatar);
  const [savingGravatar, setSavingGravatar] = useState(false);

  async function saveProfile() {
    setSaving(true);
    try {
      const res = await fetch("/api/v1/users/me", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name }),
      });
      if (res.ok) toast.success(t_common("saved"));
      else toast.error(t_common("saveFailed"));
    } finally {
      setSaving(false);
    }
  }

  async function saveBios() {
    setSavingBio(true);
    try {
      const res = await fetch("/api/v1/users/me", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          bio: bio.trim() || null,
          privateBio: privateBio.trim() || null,
        }),
      });
      if (res.ok) toast.success(t_common("saved"));
      else toast.error(t_common("saveFailed"));
    } finally {
      setSavingBio(false);
    }
  }

  const bioUnchanged = bio === (user.bio ?? "") && privateBio === (user.privateBio ?? "");

  async function saveUsername() {
    setUsernameError(null);
    if (!USERNAME_PATTERN.test(username)) {
      setUsernameError(t("usernameInvalid"));
      return;
    }
    setSavingUsername(true);
    try {
      const res = await fetch("/api/v1/users/me", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ username }),
      });
      if (res.ok) toast.success(t_common("saved"));
      else if (res.status === 409) setUsernameError(t("usernameTaken"));
      else toast.error(t_common("saveFailed"));
    } catch {
      toast.error(t_common("saveFailed"));
    } finally {
      setSavingUsername(false);
    }
  }

  async function saveUseGravatar(checked: boolean) {
    setSavingGravatar(true);
    const previous = useGravatar;
    setUseGravatar(checked);
    try {
      const res = await fetch("/api/v1/users/me", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ useGravatar: checked }),
      });
      if (res.ok) {
        // Only affects the displayed avatar for accounts without a custom
        // upload — matches the server's own condition in api/v1/users/me.
        if (!hasCustomAvatar) {
          const data = await res.json() as { avatarUrl?: string | null };
          setAvatarImage(data.avatarUrl ?? null);
        }
        toast.success(t_common("saved"));
      } else {
        setUseGravatar(previous);
        toast.error(t_common("saveFailed"));
      }
    } catch {
      setUseGravatar(previous);
      toast.error(t_common("saveFailed"));
    } finally {
      setSavingGravatar(false);
    }
  }

  async function savePrivacy(checked: boolean) {
    setSavingPrivacy(true);
    const previous = isPrivate;
    setIsPrivate(checked);
    try {
      const res = await fetch("/api/v1/users/me", {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ isPrivate: checked }),
      });
      if (res.ok) toast.success(t_common("saved"));
      else {
        setIsPrivate(previous);
        toast.error(t_common("saveFailed"));
      }
    } catch {
      setIsPrivate(previous);
      toast.error(t_common("saveFailed"));
    } finally {
      setSavingPrivacy(false);
    }
  }

  return (
    <div className="space-y-6">
      <section className="rounded-xl border p-6 space-y-4">
        <h2 className="font-semibold text-lg">{t("profile")}</h2>
        <AvatarUploader
          name={user.name}
          image={avatarImage}
          hasCustomAvatar={hasCustomAvatar}
          onChange={(image, custom) => {
            setAvatarImage(image);
            setHasCustomAvatar(custom);
          }}
        />
        <div className="flex items-center justify-between gap-3 rounded-lg border p-3">
          <div>
            <p className="text-sm font-medium">{t("useGravatar")}</p>
            <p className="text-xs text-muted-foreground max-w-prose">{t("useGravatarDescription")}</p>
          </div>
          <Switch
            id="use-gravatar"
            checked={useGravatar}
            disabled={savingGravatar}
            onCheckedChange={(checked) => { void saveUseGravatar(checked); }}
          />
        </div>
        <div className="space-y-2">
          <Label>{t("displayName")}</Label>
          <Input value={name} onChange={(e) => setName(e.target.value)} />
        </div>
        <div className="space-y-2">
          <Label>{t("email")}</Label>
          <Input value={user.email} disabled className="opacity-70" />
        </div>
        <Button onClick={saveProfile} disabled={saving || name === user.name}>
          {saving ? t("saving") : t_common("save")}
        </Button>
      </section>

      <section className="rounded-xl border p-6 space-y-4">
        <h2 className="font-semibold text-lg">{t("username")}</h2>
        <p className="text-xs text-muted-foreground">{t("usernameDescription")}</p>
        <div className="space-y-2">
          <div className="flex items-center gap-1">
            <span className="text-sm text-muted-foreground">@</span>
            <Input
              value={username}
              onChange={(e) => { setUsername(e.target.value.toLowerCase()); setUsernameError(null); }}
              maxLength={20}
              className="max-w-xs"
            />
          </div>
          {usernameError && <p className="text-xs text-destructive">{usernameError}</p>}
        </div>
        <Button onClick={saveUsername} disabled={savingUsername || username === (user.username ?? "")}>
          {savingUsername ? t("saving") : t_common("save")}
        </Button>
      </section>

      <section className="rounded-xl border p-6 space-y-4">
        <h2 className="font-semibold text-lg">{t("bio")}</h2>
        <div className="space-y-2">
          <Label>{t("publicBio")}</Label>
          <p className="text-xs text-muted-foreground">{t("publicBioDescription")}</p>
          <Textarea
            value={bio}
            onChange={(e) => setBio(e.target.value)}
            placeholder={t("publicBioPlaceholder")}
            rows={3}
            maxLength={500}
            className="resize-none"
          />
          <p className="text-xs text-muted-foreground text-right">{bio.length}/500</p>
        </div>
        <div className="space-y-2">
          <Label>{t("privateBio")}</Label>
          <p className="text-xs text-muted-foreground">{t("privateBioDescription")}</p>
          <Textarea
            value={privateBio}
            onChange={(e) => setPrivateBio(e.target.value)}
            placeholder={t("privateBioPlaceholder")}
            rows={5}
            maxLength={2000}
            className="resize-none"
          />
          <p className="text-xs text-muted-foreground text-right">{privateBio.length}/2000</p>
        </div>
        <Button onClick={saveBios} disabled={savingBio || bioUnchanged}>
          {savingBio ? t("saving") : t_common("save")}
        </Button>
      </section>

      <section className="rounded-xl border p-6 space-y-1">
        <div className="flex items-center justify-between">
          <div>
            <h2 className="font-semibold text-lg">{t("privateAccount")}</h2>
            <p className="text-sm text-muted-foreground mt-1 max-w-prose">
              {t("privateAccountDescription")}
            </p>
          </div>
          <Switch
            id="private-account"
            checked={isPrivate}
            disabled={savingPrivacy}
            onCheckedChange={(checked) => { void savePrivacy(checked); }}
          />
        </div>
      </section>

      <section className="rounded-xl border p-6 space-y-4">
        <h2 className="font-semibold text-lg">{t("language")}</h2>
        <p className="text-sm text-muted-foreground">{t("languageDescription")}</p>
        <Select
          defaultValue={user.locale}
          onValueChange={(v) => {
            void setLocale(v as Locale).then((ok) => {
              if (ok) toast.success(t_common("saved"));
              else toast.error(t_common("saveFailed"));
            });
          }}
        >
          <SelectTrigger className="w-48">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {SUPPORTED_LOCALES.map((l) => {
              const Flag = LOCALE_FLAGS[l.code];
              return (
                <SelectItem key={l.code} value={l.code}>
                  <span className="flex items-center gap-2">
                    <Flag className="h-3 w-4 rounded-[2px]" />
                    {l.label}
                  </span>
                </SelectItem>
              );
            })}
          </SelectContent>
        </Select>
      </section>
    </div>
  );
}
