'use client';

import Link from 'next/link';
import { useState, useSyncExternalStore } from 'react';
import { CheckCircle2, Loader2 } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { BrandedAuthShell } from '@/components/shared/branded-auth-shell';

interface PasswordSetFormProps {
  /** API endpoint that accepts `{ token, password }` and sets / resets the password. */
  endpoint: string;
  title: string;
  description: string;
  successTitle: string;
  successDescription: string;
  submitLabel: string;
}

const MIN_LENGTH = 9;

/**
 * Shared form used by both the activation and password-reset flows.
 *
 * The activation/reset token is read from the URL fragment (`#token=…`)
 * - not the query string - so the token never travels to the server,
 * never lands in proxy / reverse-proxy logs, never sits in the Referer
 * header, and is invisible to upstream CDN/cache layers. The browser
 * still sends it on form-submit via the explicit POST body.
 *
 * Pre-2026-05-14 the token was passed as `?token=…`; the legacy
 * search-param read is kept as a fallback so links sent before the
 * switchover still work for the remaining TTL.
 *
 * Empty / missing tokens land the user in an explicit error state
 * instead of submitting a doomed request.
 */
function readTokenFromUrl(): string {
  if (typeof window === 'undefined') return '';
  const hash = window.location.hash.replace(/^#/, '');
  if (hash) {
    const params = new URLSearchParams(hash);
    const fromFragment = params.get('token');
    if (fromFragment) return fromFragment;
  }
  // Back-compat: pre-fragment links still carry `?token=…`. Drop after
  // every outstanding activation/reset link past TTL has been consumed.
  const search = new URLSearchParams(window.location.search);
  return search.get('token') ?? '';
}

// Tiny no-op subscriber - we don't actually need to react to
// hashchange events (the token is set once when the user lands on the
// page). The store integration is here so React knows the source is
// external and skips the SSR / hydration mismatch warning.
const subscribe = () => () => undefined;

export function PasswordSetForm({
  endpoint,
  title,
  description,
  successTitle,
  successDescription,
  submitLabel,
}: PasswordSetFormProps) {
  // Read the token via useSyncExternalStore - fragment is client-only
  // so the server-snapshot returns `null` and the client snapshot reads
  // window.location.hash post-hydration. `null` distinguishes "not yet
  // hydrated" from "missing"; empty string means "hydrated, none found".
  const token = useSyncExternalStore<string | null>(
    subscribe,
    () => readTokenFromUrl(),
    () => null,
  );

  const [password, setPassword] = useState('');
  const [confirm, setConfirm] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [done, setDone] = useState(false);

  const tooShort = password.length > 0 && password.length < MIN_LENGTH;
  const mismatch = confirm.length > 0 && password !== confirm;
  const canSubmit = !!token && password.length >= MIN_LENGTH && password === confirm && !loading;

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (!canSubmit) return;
    setLoading(true);
    setError('');
    try {
      const res = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ token, password }),
      });
      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        setError((data as { error?: string }).error ?? 'Something went wrong. Please try again.');
        return;
      }
      setDone(true);
    } catch {
      setError('Unable to connect. Please try again.');
    } finally {
      setLoading(false);
    }
  }

  if (token === null) {
    return (
      <BrandedAuthShell>
        <div className="text-center text-sm text-gray-500">Loading…</div>
      </BrandedAuthShell>
    );
  }

  if (!token) {
    return (
      <BrandedAuthShell>
        <div className="text-center space-y-3">
          <h1 className="text-xl font-semibold text-gray-900">Link is missing or invalid</h1>
          <p className="text-sm text-gray-500">
            Please use the link from the email we sent you. If the link is broken, request a new
            one.
          </p>
          <Link
            href="/portal/forgot-password"
            className="inline-block text-sm text-[#0058b3] underline-offset-2 underline hover:no-underline"
          >
            Request a new link
          </Link>
        </div>
      </BrandedAuthShell>
    );
  }

  if (done) {
    return (
      <BrandedAuthShell>
        <div className="text-center">
          <div className="inline-flex items-center justify-center w-14 h-14 rounded-full bg-green-50 mb-4">
            <CheckCircle2 className="h-7 w-7 text-green-600" />
          </div>
          <h1 className="text-xl font-semibold text-gray-900 mb-2">{successTitle}</h1>
          <p className="text-gray-500 text-sm">{successDescription}</p>
          <Link
            href="/portal/login"
            className="mt-6 inline-block text-sm text-[#0058b3] underline-offset-2 underline hover:no-underline"
          >
            Sign in
          </Link>
        </div>
      </BrandedAuthShell>
    );
  }

  return (
    <BrandedAuthShell>
      <div className="mb-6">
        <h1 className="text-xl font-semibold text-gray-900">{title}</h1>
        <p className="text-sm text-gray-500 mt-1">{description}</p>
      </div>

      <form onSubmit={handleSubmit} className="space-y-4">
        <div className="space-y-1.5">
          <Label htmlFor="password">New password</Label>
          <Input
            id="password"
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            required
            autoFocus
            autoComplete="new-password"
            minLength={MIN_LENGTH}
            disabled={loading}
          />
          <p className="text-xs text-gray-500">At least {MIN_LENGTH} characters.</p>
          {tooShort && (
            <p className="text-xs text-red-600">
              Password must be at least {MIN_LENGTH} characters.
            </p>
          )}
        </div>

        <div className="space-y-1.5">
          <Label htmlFor="confirm">Confirm password</Label>
          <Input
            id="confirm"
            type="password"
            value={confirm}
            onChange={(e) => setConfirm(e.target.value)}
            required
            autoComplete="new-password"
            disabled={loading}
          />
          {mismatch && <p className="text-xs text-red-600">Passwords don&apos;t match.</p>}
        </div>

        {error && <p className="text-sm text-red-600">{error}</p>}

        <Button
          type="submit"
          className="w-full bg-[#007bff] hover:bg-[#0069d9] text-white"
          disabled={!canSubmit}
        >
          {loading ? (
            <>
              <Loader2 className="h-4 w-4 mr-2 animate-spin" />
              Saving…
            </>
          ) : (
            submitLabel
          )}
        </Button>
      </form>
    </BrandedAuthShell>
  );
}
