import axios from 'axios';
import router from './router';
import { clearStaffSession, reconcileStaffSessionFromToken, useAuthStore } from './stores/auth';
import { ensureStaffSession, resetStaffSessionHydration } from './utils/session-hydrate';
import { ADMIN_LOCALE_STORAGE_KEY } from './i18n';

const api = axios.create({ baseURL: '/api' });

let handlingAuthInvalid = false;
let handling403Portal = false;

const PORTAL_MISMATCH_CODES = new Set(['ADMIN_ACCESS_ONLY', 'AGENT_ACCESS_ONLY']);

function requestPath(config: { url?: string; baseURL?: string } | undefined): string {
  if (!config?.url) return '';
  const base = config.baseURL ?? '';
  return `${base}${config.url}`;
}

function isLoginRequest(config: { url?: string; baseURL?: string } | undefined): boolean {
  return requestPath(config).includes('/auth/login');
}

function isInvalidCredentialsResponse(data: unknown): boolean {
  return (
    typeof data === 'object' &&
    data !== null &&
    'code' in data &&
    (data as { code?: unknown }).code === 'INVALID_CREDENTIALS'
  );
}

async function redirectToLoginForInvalidSession() {
  if (handlingAuthInvalid) return;
  handlingAuthInvalid = true;
  try {
    clearStaffSession();
    resetStaffSessionHydration();
    if (router.currentRoute.value.path !== '/login') {
      await router.replace('/login');
    }
  } finally {
    handlingAuthInvalid = false;
  }
}

let _lastReconciledToken: string | null = null;

api.interceptors.request.use((config) => {
  const t = localStorage.getItem('manage_token');
  if (t) config.headers.Authorization = `Bearer ${t}`;

  const locale = localStorage.getItem(ADMIN_LOCALE_STORAGE_KEY) || 'zh-CN';
  config.headers['X-Locale'] = locale;

  // 只在 token 变更时才重新 decode JWT + reconcile，避免并发请求时多次执行同步开销
  if (t !== _lastReconciledToken) {
    reconcileStaffSessionFromToken();
    _lastReconciledToken = t;
  }
  const auth = useAuthStore();
  const path = requestPath(config);

  if (path.includes('/admin/') && auth.isAgent.value) {
    return Promise.reject(
      Object.assign(new Error('Agent portal blocked admin API'), {
        isPortalMismatch: true,
        blockedPath: path,
      }),
    );
  }
  if (path.includes('/agent/') && auth.isAdmin.value) {
    return Promise.reject(
      Object.assign(new Error('Admin portal blocked agent API'), {
        isPortalMismatch: true,
        blockedPath: path,
      }),
    );
  }

  return config;
});

api.interceptors.response.use(
  async (res) => {
    if (!isLoginRequest(res.config) && isInvalidCredentialsResponse(res.data)) {
      await redirectToLoginForInvalidSession();
      return Promise.reject(
        Object.assign(new Error((res.data as { error?: string }).error || 'Invalid credentials'), {
          response: res,
          config: res.config,
        }),
      );
    }
    return res;
  },
  async (err) => {
    if (err.isPortalMismatch) {
      await ensureStaffSession();
      if (router.currentRoute.value.path !== '/login') {
        await router.replace('/');
      }
      return Promise.reject(err);
    }

    if (
      !isLoginRequest(err.config) &&
      (err.response?.status === 401 || isInvalidCredentialsResponse(err.response?.data))
    ) {
      await redirectToLoginForInvalidSession();
    }

    if (
      err.response?.status === 403 &&
      !handling403Portal &&
      PORTAL_MISMATCH_CODES.has(err.response?.data?.code)
    ) {
      handling403Portal = true;
      await ensureStaffSession();
      handling403Portal = false;

      const auth = useAuthStore();
      const path = requestPath(err.config);
      const isAdminApi = path.includes('/admin/');
      const isAgentApi = path.includes('/agent/');

      if ((isAdminApi && auth.isAgent.value) || (isAgentApi && auth.isAdmin.value)) {
        if (router.currentRoute.value.path !== '/login') {
          await router.replace('/');
        }
        return Promise.reject(err);
      }

      if (err.config) {
        return api.request(err.config);
      }

      clearStaffSession();
      if (router.currentRoute.value.path !== '/login') {
        await router.replace('/login');
      }
    }

    return Promise.reject(err);
  },
);

export default api;
