import {
  createContext,
  PropsWithChildren,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from 'react';

import { apiFetch } from '@/lib/api-client';
import { getApiErrorMessage } from '@/lib/api-errors';
import type { StoredSession } from '@/lib/auth-storage';
import { clearSession, loadSession, saveSession } from '@/lib/auth-storage';

type LoginResponseData = {
  auth_token: string;
  tenant_id: string;
  user_id: string;
};

type AuthContextValue = {
  ready: boolean;
  session: StoredSession | null;
  login: (loginId: string, password: string) => Promise<{ ok: true } | { ok: false; message: string }>;
  logout: () => Promise<void>;
  refreshSession: () => Promise<void>;
};

const AuthContext = createContext<AuthContextValue | null>(null);

export function AuthProvider({ children }: PropsWithChildren) {
  const [ready, setReady] = useState(false);
  const [session, setSession] = useState<StoredSession | null>(null);

  const refreshSession = useCallback(async () => {
    const s = await loadSession();
    setSession(s);
  }, []);

  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const s = await loadSession();
        if (!cancelled) setSession(s);
      } finally {
        if (!cancelled) setReady(true);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, []);

  const login = useCallback(async (loginId: string, password: string) => {
    const trimmedId = loginId.trim();
    const trimmedPw = password;
    if (!trimmedId || !trimmedPw) {
      return { ok: false as const, message: 'ログインIDとパスワードを入力してください。' };
    }

    try {
      // mixhost WAF: "demo123"/"2026" 等は遮断されるが "MachiRcpt" は pw 平文で送信可能
      const form = new URLSearchParams({
        login_id: trimmedId,
        pw: trimmedPw,
      });
      const httpRes = await apiFetch('/login.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: form.toString(),
      });
      const text = (await httpRes.text()).trim();
      let res: { ok: boolean; data?: LoginResponseData; error?: { message?: string } };
      try {
        res = text ? JSON.parse(text) : { ok: false };
      } catch {
        return {
          ok: false as const,
          message: 'サーバーから JSON 以外の応答が返りました。',
        };
      }

      if (!res.ok) {
        return {
          ok: false as const,
          message: getApiErrorMessage(res, `ログインに失敗しました (HTTP ${httpRes.status})。`),
        };
      }

      if (!res.data?.auth_token) {
        return { ok: false as const, message: 'ログイン応答の形式が不正です。' };
      }

      const next: StoredSession = {
        authToken: res.data.auth_token,
        tenantId: res.data.tenant_id,
        userId: res.data.user_id,
      };
      await saveSession(next);
      setSession(next);
      return { ok: true as const };
    } catch (e) {
      const message = e instanceof Error ? e.message : '通信に失敗しました。';
      return { ok: false as const, message };
    }
  }, []);

  const logout = useCallback(async () => {
    await clearSession();
    setSession(null);
  }, []);

  const value = useMemo<AuthContextValue>(
    () => ({
      ready,
      session,
      login,
      logout,
      refreshSession,
    }),
    [ready, session, login, logout, refreshSession]
  );

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

export function useAuth(): AuthContextValue {
  const ctx = useContext(AuthContext);
  if (!ctx) {
    throw new Error('useAuth は AuthProvider 内で使用してください。');
  }
  return ctx;
}
