import { ErrorCode, type HouseView, renameHouseSchema } from "@batch-cooking/shared";
import { type FormEvent, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import { ApiError, apiClient } from "../../api/client";
import { HouseNameField } from "../../features/profile/HouseNameField";
import { fieldErrorsFrom } from "../../lib/zod-errors";
import { errorMessageService } from "../../services/error-message.service";
import "./onboarding.scss";

/**
 * Second step of the post-signup onboarding wizard, routed at
 * `/onboarding/foyer` — unlike the regime/allergens steps, this one is
 * genuinely optional rather than just "skippable via an unedited default":
 * no household is created at signup anymore (see the API's
 * `auth.service.ts`), so there's nothing to prefill or implicitly keep by
 * pressing "Continuer" — the visitor explicitly creates one, joins one by
 * invite code, or skips the step outright via {@link SkipButton}.
 *
 * Still checks `getCurrentHouse()` on mount and skips straight to the
 * "already have one" state if it finds one — defensive against revisiting
 * this step (e.g. browser back) after already creating/joining a
 * household earlier in the same wizard run.
 */
export function OnboardingHouseholdPage() {
  const { t } = useTranslation();
  const navigate = useNavigate();

  const [isLoading, setIsLoading] = useState(true);
  const [house, setHouse] = useState<HouseView | null>(null);

  useEffect(() => {
    let cancelled = false;
    apiClient
      .getCurrentHouse()
      .then((result) => {
        if (!cancelled) setHouse(result);
      })
      // Not essential for this step to render — `house` just stays `null`
      // (same as a genuinely household-less profile) rather than
      // stranding the visitor over a transient failure, same reasoning as
      // OnboardingSourcesPage's own catch.
      .catch(() => {})
      .finally(() => {
        if (!cancelled) setIsLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, []);

  /**
   * A household is what the next step (`/onboarding/sources`) needs to
   * attach a preference to — created/joined/already-there goes on to it,
   * skipped goes straight to `/onboarding/allergenes` instead (nothing to
   * configure sources for without a household).
   */
  function goToNextStep(hasHousehold: boolean) {
    void navigate(hasHousehold ? "/onboarding/sources" : "/onboarding/allergenes");
  }

  return (
    <main className="onboarding-page">
      <div className="onboarding-card">
        <p className="onboarding-step">{t("onboarding.step", { current: 2, total: 3 })}</p>
        <h1>{t("onboarding.household.title")}</h1>

        {isLoading ? (
          <p>{t("onboarding.loading")}</p>
        ) : house !== null ? (
          <>
            <p>{t("onboarding.household.alreadyHasHouse", { name: house.name })}</p>
            <button type="button" onClick={() => goToNextStep(true)}>
              {t("onboarding.continue")}
            </button>
          </>
        ) : (
          <>
            <p className="onboarding-subtitle">{t("onboarding.household.subtitle")}</p>
            <CreateHouseholdForm onDone={() => goToNextStep(true)} />
            <JoinHouseholdForm onDone={() => goToNextStep(true)} />
            <SkipButton onSkip={() => goToNextStep(false)} />
          </>
        )}
      </div>
    </main>
  );
}

function CreateHouseholdForm({ onDone }: { onDone: () => void }) {
  const { t } = useTranslation();
  const [name, setName] = useState("");
  const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
  const [formError, setFormError] = useState<string | null>(null);
  const [isSubmitting, setIsSubmitting] = useState(false);

  async function handleSubmit(e: FormEvent) {
    e.preventDefault();
    setFormError(null);
    const result = renameHouseSchema.safeParse({ name });
    if (!result.success) {
      setFieldErrors(fieldErrorsFrom(result.error));
      return;
    }
    setFieldErrors({});
    setIsSubmitting(true);
    try {
      await apiClient.createHouse(result.data.name);
      onDone();
    } catch (err) {
      const code = err instanceof ApiError ? err.code : ErrorCode.INTERNAL_ERROR;
      setFormError(errorMessageService.getLabel(code));
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    <form onSubmit={handleSubmit} noValidate>
      <h2>{t("household.noHouse.createTitle")}</h2>
      <HouseNameField value={name} onChange={setName} error={fieldErrors.name} />
      {formError && <p className="form-error">{formError}</p>}
      <button type="submit" disabled={isSubmitting}>
        {t("household.noHouse.createButton")}
      </button>
    </form>
  );
}

function JoinHouseholdForm({ onDone }: { onDone: () => void }) {
  const { t } = useTranslation();
  const [inviteCode, setInviteCode] = useState("");
  const [formError, setFormError] = useState<string | null>(null);
  const [isSubmitting, setIsSubmitting] = useState(false);

  async function handleSubmit(e: FormEvent) {
    e.preventDefault();
    setFormError(null);
    setIsSubmitting(true);
    try {
      await apiClient.joinHouse(inviteCode.trim());
      onDone();
    } catch (err) {
      const code = err instanceof ApiError ? err.code : ErrorCode.INTERNAL_ERROR;
      setFormError(errorMessageService.getLabel(code));
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    <form onSubmit={handleSubmit} noValidate>
      <h2>{t("household.noHouse.joinTitle")}</h2>
      <label htmlFor="inviteCode">{t("household.noHouse.joinLabel")}</label>
      <input
        id="inviteCode"
        value={inviteCode}
        onChange={(e) => setInviteCode(e.target.value.toUpperCase())}
        autoComplete="off"
      />
      {formError && <p className="form-error">{formError}</p>}
      <button type="submit" disabled={isSubmitting || inviteCode.trim().length === 0}>
        {t("household.noHouse.joinButton")}
      </button>
    </form>
  );
}

/** No API call — skipping just moves on, same "nothing to persist" idea as the regime/allergens steps' own skippability. */
function SkipButton({ onSkip }: { onSkip: () => void }) {
  const { t } = useTranslation();
  return (
    <button type="button" className="onboarding-skip" onClick={onSkip}>
      {t("onboarding.household.skip")}
    </button>
  );
}
