// ============================================================================
// AUTH SERVICE — API calls; tokens stored in localStorage (see shared/utils/token)
// ============================================================================

import { env } from '@/shared/config/env';
import {
  clearAccessToken as clearStoredToken,
  getAccessToken,
  setAccessToken as setStoredToken,
} from '@/shared/utils/token';
import type { Role } from '@/lib/permissions';
import type { StaffProfileDto } from '@/components/profile/types';
import { mapStaffProfileDto } from '@/lib/user-profile-service';

const API_URL = env.API_URL.replace(/\/$/, '');
const AUTH_BASE = `${API_URL}/api/v1/auth`;

export type AuthUser = {
  id: string;
  email: string;
  name?: string;
  roles: Role[];
  phone?: string | null;
  staffProfile?: StaffProfileDto;
  /** False until user completes email verification (may be omitted for older API responses). */
  emailVerified?: boolean;
};

export type AuthProfile = AuthUser;

function attachStaffFromBody(u: AuthUser, body: Record<string, unknown>): AuthUser {
  const sp = mapStaffProfileDto(body.staffProfile as Record<string, unknown> | undefined);
  return sp ? { ...u, staffProfile: sp } : u;
}

/** FastAPI: detail string, or validation array with { msg } entries. */
function parseFastApiErrorDetail(body: unknown): { summary: string; reasons: string[] } {
  if (!body || typeof body !== 'object') {
    return { summary: 'Yêu cầu thất bại', reasons: ['Yêu cầu thất bại'] };
  }
  const d = (body as { detail?: unknown }).detail;
  if (typeof d === 'string') {
    const s = d.trim() || 'Yêu cầu thất bại';
    return { summary: s, reasons: [s] };
  }
  if (Array.isArray(d)) {
    const reasons = d
      .map((e) => {
        if (typeof e === 'string') return e.trim();
        if (e && typeof e === 'object' && 'msg' in e) {
          const m = (e as { msg?: unknown }).msg;
          return typeof m === 'string' ? m.trim() : String(m);
        }
        return '';
      })
      .filter((s) => s.length > 0);
    const dedup = [...new Set(reasons)];
    const summary = dedup[0] ?? 'Yêu cầu thất bại';
    return { summary, reasons: dedup.length ? dedup : [summary] };
  }
  return { summary: 'Yêu cầu thất bại', reasons: ['Yêu cầu thất bại'] };
}

function parseFastApiError(body: unknown): string {
  return parseFastApiErrorDetail(body).summary;
}

export const authService = {
  async login(email: string, password: string) {
    const res = await fetch(`${AUTH_BASE}/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({ email, password }),
    });

    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false as const, error: parseFastApiError(body), user: null };
    }

    setStoredToken(body.accessToken);
    const base = body.user as AuthUser;
    return { success: true as const, error: null, user: attachStaffFromBody(base, body.user as Record<string, unknown>) };
  },

  async register(payload: {
    fullName: string;
    email: string;
    password: string;
    passwordConfirm: string;
    employeeId: string;
    academicTitleCode: string;
    academicTitleOther?: string | null;
    unitId?: string | null;
    unitNameFreetext?: string | null;
    jobTitle: string;
  }): Promise<
    | {
        success: true;
        error: null;
        user: AuthUser;
        accessToken: string;
      }
    | {
        success: true;
        error: null;
        user: AuthUser;
        accessToken: null;
        emailVerificationRequired: true;
        message: string;
        email: string;
        otpTtlSeconds?: number;
        otpDeliveryChannel?: 'smtp' | 'log_only' | 'none' | 'smtp_failed';
      }
    | {
        success: false;
        error: string;
        rejectionReasons: string[];
        httpStatus: number;
        user: null;
      }
  > {
    const res = await fetch(`${AUTH_BASE}/register`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({
        fullName: payload.fullName,
        email: payload.email,
        password: payload.password,
        passwordConfirm: payload.passwordConfirm,
        employeeId: payload.employeeId,
        academicTitleCode: payload.academicTitleCode,
        academicTitleOther: payload.academicTitleOther ?? undefined,
        unitId: payload.unitId ?? undefined,
        unitNameFreetext: payload.unitNameFreetext ?? undefined,
        jobTitle: payload.jobTitle,
      }),
    });

    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      const parsed = parseFastApiErrorDetail(body);
      return {
        success: false as const,
        error: parsed.summary,
        rejectionReasons: parsed.reasons,
        httpStatus: res.status,
        user: null,
      };
    }

    const raw = body as Record<string, unknown>;
    if (raw.emailVerificationRequired === true) {
      const u = raw.user as Record<string, unknown> | undefined;
      const base =
        u && typeof u === 'object'
          ? ({
              id: String(u.id ?? ''),
              email: String(u.email ?? ''),
              name: u.name != null ? String(u.name) : undefined,
              roles: (Array.isArray(u.roles) ? u.roles : []) as Role[],
              phone: u.phone != null ? String(u.phone) : null,
              emailVerified: Boolean(u.emailVerified),
            } as AuthUser)
          : ({ id: '', email: '', roles: [] as Role[] } as AuthUser);
      const withStaff = u ? attachStaffFromBody(base, u as Record<string, unknown>) : base;
      const msg = typeof raw.message === 'string' ? raw.message : '';
      const em = typeof raw.email === 'string' ? raw.email : payload.email.trim().toLowerCase();
      const otpTtlRaw = raw.otpTtlSeconds;
      const otpTtlSeconds =
        typeof otpTtlRaw === 'number' && Number.isFinite(otpTtlRaw) && otpTtlRaw > 0
          ? Math.floor(otpTtlRaw)
          : undefined;
      const otpDelRaw = raw.otpDeliveryChannel;
      const otpDeliveryChannel =
        otpDelRaw === 'smtp' ||
        otpDelRaw === 'log_only' ||
        otpDelRaw === 'none' ||
        otpDelRaw === 'smtp_failed'
          ? otpDelRaw
          : undefined;
      return {
        success: true as const,
        error: null,
        user: withStaff,
        accessToken: null,
        emailVerificationRequired: true as const,
        message: msg,
        email: em,
        otpTtlSeconds,
        otpDeliveryChannel,
      };
    }

    const token = typeof raw.accessToken === 'string' ? raw.accessToken : '';
    if (token) setStoredToken(token);
    const base = raw.user as AuthUser;
    return {
      success: true as const,
      error: null,
      user: attachStaffFromBody(base, raw.user as Record<string, unknown>),
      accessToken: token,
    };
  },

  async verifyEmail(token: string): Promise<{ success: true; message: string } | { success: false; error: string }> {
    const res = await fetch(`${AUTH_BASE}/verify-email`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({ token }),
    });
    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false as const, error: parseFastApiError(body) };
    }
    const msg = typeof (body as { message?: unknown }).message === 'string' ? (body as { message: string }).message : '';
    return { success: true as const, message: msg };
  },

  async resendVerificationEmail(email: string): Promise<{ success: true; message: string } | { success: false; error: string }> {
    const res = await fetch(`${AUTH_BASE}/resend-verification`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({ email }),
    });
    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false as const, error: parseFastApiError(body) };
    }
    const msg = typeof (body as { message?: unknown }).message === 'string' ? (body as { message: string }).message : '';
    return { success: true as const, message: msg };
  },

  async verifyRegistrationOtp(payload: {
    email: string;
    otp: string;
  }): Promise<{ success: true; message: string } | { success: false; error: string }> {
    const res = await fetch(`${AUTH_BASE}/verify-otp`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({
        email: payload.email.trim().toLowerCase(),
        otp: payload.otp.trim(),
      }),
    });
    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false as const, error: parseFastApiError(body) };
    }
    const msg = typeof (body as { message?: unknown }).message === 'string' ? (body as { message: string }).message : '';
    return { success: true as const, message: msg };
  },

  async resendRegistrationOtp(email: string): Promise<{ success: true; message: string } | { success: false; error: string }> {
    const res = await fetch(`${AUTH_BASE}/resend-otp`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({ email: email.trim().toLowerCase() }),
    });
    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false as const, error: parseFastApiError(body) };
    }
    const msg = typeof (body as { message?: unknown }).message === 'string' ? (body as { message: string }).message : '';
    return { success: true as const, message: msg };
  },

  async logout() {
    try {
      await fetch(`${AUTH_BASE}/logout`, {
        method: 'POST',
        credentials: 'include',
      });
    } catch (err) {
      console.error('Logout error:', err);
    } finally {
      clearStoredToken();
    }
  },

  authHeaders() {
    const token = getAccessToken();
    if (!token) return null;
    return {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
    } as const;
  },

  async getProfile(): Promise<{ success: true; profile: AuthProfile } | { success: false; error: string }> {
    const h = this.authHeaders();
    if (!h) {
      return { success: false, error: 'Chưa đăng nhập.' };
    }
    const res = await fetch(`${AUTH_BASE}/me`, { credentials: 'include', headers: h });
    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false, error: parseFastApiError(body) };
    }
    const b = body as Record<string, unknown>;
    const base = b as AuthProfile;
    return { success: true, profile: attachStaffFromBody(base, b) };
  },

  async updateProfile(payload: {
    fullName?: string;
    phone?: string | null;
    employeeId?: string | null;
    academicTitleCode?: string | null;
    academicTitleOther?: string | null;
    unitId?: string | null;
    unitNameFreetext?: string | null;
    jobTitle?: string | null;
  }): Promise<{ success: true; profile: AuthProfile } | { success: false; error: string }> {
    const h = this.authHeaders();
    if (!h) {
      return { success: false, error: 'Chưa đăng nhập.' };
    }
    const body: Record<string, string | null | undefined> = {};
    if (payload.fullName !== undefined) body.fullName = payload.fullName;
    if (payload.phone !== undefined) body.phone = payload.phone;
    if (payload.employeeId !== undefined) body.employeeId = payload.employeeId;
    if (payload.academicTitleCode !== undefined) body.academicTitleCode = payload.academicTitleCode;
    if (payload.academicTitleOther !== undefined) body.academicTitleOther = payload.academicTitleOther;
    if (payload.unitId !== undefined) body.unitId = payload.unitId;
    if (payload.unitNameFreetext !== undefined) body.unitNameFreetext = payload.unitNameFreetext;
    if (payload.jobTitle !== undefined) body.jobTitle = payload.jobTitle;

    const res = await fetch(`${AUTH_BASE}/profile`, {
      method: 'PATCH',
      credentials: 'include',
      headers: h,
      body: JSON.stringify(body),
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false, error: parseFastApiError(data) };
    }
    const d = data as Record<string, unknown>;
    const base = d as AuthProfile;
    return { success: true, profile: attachStaffFromBody(base, d) };
  },

  async submitProfileVerification(): Promise<
    { success: true; profile: AuthProfile } | { success: false; error: string }
  > {
    const h = this.authHeaders();
    if (!h) {
      return { success: false, error: 'Chưa đăng nhập.' };
    }
    const res = await fetch(`${AUTH_BASE}/profile/submit-verification`, {
      method: 'POST',
      headers: h,
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false, error: parseFastApiError(data) };
    }
    const d = data as Record<string, unknown>;
    const base = d as AuthProfile;
    return { success: true, profile: attachStaffFromBody(base, d) };
  },

  async changePassword(payload: {
    currentPassword: string;
    newPassword: string;
    newPasswordConfirm: string;
  }): Promise<
    { success: true; accessToken: string; user: AuthUser } | { success: false; error: string }
  > {
    const h = this.authHeaders();
    if (!h) {
      return { success: false, error: 'Chưa đăng nhập.' };
    }
    const res = await fetch(`${AUTH_BASE}/change-password`, {
      method: 'POST',
      credentials: 'include',
      headers: h,
      body: JSON.stringify({
        currentPassword: payload.currentPassword,
        newPassword: payload.newPassword,
        newPasswordConfirm: payload.newPasswordConfirm,
      }),
    });
    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false, error: parseFastApiError(body) };
    }
    setStoredToken(body.accessToken);
    const base = body.user as AuthUser;
    return {
      success: true,
      accessToken: body.accessToken,
      user: attachStaffFromBody(base, body.user as Record<string, unknown>),
    };
  },

  async requestPasswordReset(email: string) {
    const res = await fetch(`${AUTH_BASE}/forgot-password`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify({ email }),
    });
    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false as const, error: parseFastApiError(body), message: null as string | null };
    }
    const msg = typeof (body as { message?: unknown }).message === 'string' ? (body as { message: string }).message : '';
    return { success: true as const, error: null, message: msg };
  },

  async confirmPasswordReset(payload: {
    token: string;
    newPassword: string;
    newPasswordConfirm: string;
  }) {
    const res = await fetch(`${AUTH_BASE}/reset-password`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include',
      body: JSON.stringify(payload),
    });
    const body = await res.json().catch(() => ({}));
    if (!res.ok) {
      return { success: false as const, error: parseFastApiError(body), message: null as string | null };
    }
    const msg = typeof (body as { message?: unknown }).message === 'string' ? (body as { message: string }).message : '';
    return { success: true as const, error: null, message: msg };
  },

  async refreshSession() {
    const token = getAccessToken();
    if (!token) {
      return { success: false, user: null };
    }
    try {
      const res = await fetch(`${AUTH_BASE}/refresh`, {
        method: 'POST',
        credentials: 'include',
        headers: { Authorization: `Bearer ${token}` },
      });

      if (res.ok) {
        const data = await res.json();
        setStoredToken(data.accessToken);
        const u = data.user as AuthUser;
        return {
          success: true,
          user: attachStaffFromBody(u, data.user as Record<string, unknown>),
        };
      }
      clearStoredToken();
      return { success: false, user: null };
    } catch (err) {
      console.error('Session refresh failed:', err);
      clearStoredToken();
      return { success: false, user: null };
    }
  },
};
