import { getMe, refreshSession } from "@/features/auth/api";
import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints";
import { apiRequest, getAccessToken } from "@/shared/api/request";
import { FINANCE_OPERATIONS, FINANCE_PERMISSIONS, WALLET_IDENTITIES } from "./constants.js";
import { normalizeApplicationPage, normalizeRechargeBillPage, normalizeWithdrawalApplicationPage } from "./format.js";

const appCodeHeader = "X-App-Code";

export async function fetchFinanceSession() {
  const session = await currentSession();
  const permissions = Array.isArray(session.permissions) ? session.permissions : [];
  const canCreateApplication = permissions.includes(FINANCE_PERMISSIONS.createApplication);
  const canAuditApplication = permissions.includes(FINANCE_PERMISSIONS.auditApplication);
  const canAuditWithdrawalApplications =
    permissions.includes(FINANCE_PERMISSIONS.auditWithdrawalApplications) || permissions.includes(FINANCE_PERMISSIONS.auditApplication);
  const canViewWithdrawalApplications = permissions.includes(FINANCE_PERMISSIONS.viewWithdrawalApplications) || canAuditWithdrawalApplications;
  const canViewAppRechargeDetails = permissions.includes(FINANCE_PERMISSIONS.viewAppRechargeDetails);

  return {
    ...session,
    canAccessFinance: canCreateApplication || canAuditApplication || canViewWithdrawalApplications || canViewAppRechargeDetails,
    canAuditApplication,
    canAuditWithdrawalApplications,
    canCreateApplication,
    canViewAppRechargeDetails,
    canViewWithdrawalApplications,
    permissions
  };
}

export async function fetchFinanceApplicationOptions() {
  const endpoint = API_ENDPOINTS.listApps;
  const data = await apiRequest(apiEndpointPath(API_OPERATIONS.listApps), {
    method: endpoint.method
  });
  return normalizeOptions({ apps: data });
}

export async function listFinanceApplications(query = {}) {
  const endpoint = API_ENDPOINTS.listFinanceApplications;
  const data = await apiRequest(apiEndpointPath(API_OPERATIONS.listFinanceApplications), {
    method: endpoint.method,
    query
  });
  return normalizeApplicationPage(data);
}

export async function listMyFinanceApplications(query = {}) {
  const endpoint = API_ENDPOINTS.listMyFinanceApplications;
  const data = await apiRequest(apiEndpointPath(API_OPERATIONS.listMyFinanceApplications), {
    method: endpoint.method,
    query
  });
  return normalizeApplicationPage(data);
}

export async function listFinanceWithdrawalApplications(query = {}) {
  const endpoint = API_ENDPOINTS.listFinanceWithdrawalApplications;
  const data = await apiRequest(apiEndpointPath(API_OPERATIONS.listFinanceWithdrawalApplications), {
    method: endpoint.method,
    query
  });
  return normalizeWithdrawalApplicationPage(data);
}

export async function listFinanceRechargeDetails(query = {}, apps = []) {
  const page = positiveInteger(query.page, 1);
  const pageSize = positiveInteger(query.page_size ?? query.pageSize, 50);
  const selectedAppCode = stringValue(query.app_code ?? query.appCode);
  const cleanQuery = cleanRechargeBillQuery(query);

  if (selectedAppCode) {
    const data = await listRechargeBillsForApp(selectedAppCode, { ...cleanQuery, page, page_size: pageSize });
    return { ...data, page, pageSize };
  }

  const appCodes = normalizeApps(apps).map((app) => app.appCode);
  if (!appCodes.length) {
    return { items: [], page, pageSize, total: 0 };
  }

  const mergedPageSize = page * pageSize;
  const pages = await Promise.all(
    appCodes.map((appCode) => listRechargeBillsForApp(appCode, { ...cleanQuery, page: 1, page_size: mergedPageSize }))
  );
  const items = pages
    .flatMap((data) => data.items || [])
    .sort((left, right) => (right.createdAtMs || 0) - (left.createdAtMs || 0) || String(right.transactionId).localeCompare(String(left.transactionId)));
  const start = (page - 1) * pageSize;

  return {
    items: items.slice(start, start + pageSize),
    page,
    pageSize,
    total: pages.reduce((sum, data) => sum + Number(data.total || 0), 0)
  };
}

export async function createFinanceApplication(payload) {
  const endpoint = API_ENDPOINTS.createFinanceApplication;
  return apiRequest(apiEndpointPath(API_OPERATIONS.createFinanceApplication), {
    body: payload,
    method: endpoint.method
  });
}

export async function approveFinanceApplication(applicationId, payload) {
  const endpoint = API_ENDPOINTS.approveFinanceApplication;
  return apiRequest(apiEndpointPath(API_OPERATIONS.approveFinanceApplication, { application_id: applicationId }), {
    body: payload,
    method: endpoint.method
  });
}

export async function rejectFinanceApplication(applicationId, payload) {
  const endpoint = API_ENDPOINTS.rejectFinanceApplication;
  return apiRequest(apiEndpointPath(API_OPERATIONS.rejectFinanceApplication, { application_id: applicationId }), {
    body: payload,
    method: endpoint.method
  });
}

export async function approveFinanceWithdrawalApplication(applicationId, payload) {
  const endpoint = API_ENDPOINTS.approveFinanceWithdrawalApplication;
  return apiRequest(apiEndpointPath(API_OPERATIONS.approveFinanceWithdrawalApplication, { application_id: applicationId }), {
    body: payload,
    method: endpoint.method
  });
}

export async function rejectFinanceWithdrawalApplication(applicationId, payload) {
  const endpoint = API_ENDPOINTS.rejectFinanceWithdrawalApplication;
  return apiRequest(apiEndpointPath(API_OPERATIONS.rejectFinanceWithdrawalApplication, { application_id: applicationId }), {
    body: payload,
    method: endpoint.method
  });
}

export function filterOperationsByPermissions(operations, permissions) {
  const allowed = new Set(permissions || []);
  return (operations || []).filter((operation) => !operation.permissionCode || allowed.has(operation.permissionCode));
}

async function currentSession() {
  try {
    return await refreshSession();
  } catch {
    if (getAccessToken()) {
      return getMe();
    }
    throw new Error("登录已失效");
  }
}

async function listRechargeBillsForApp(appCode, query = {}) {
  const endpoint = API_ENDPOINTS.listRechargeBills;
  const data = await apiRequest(apiEndpointPath(API_OPERATIONS.listRechargeBills), {
    headers: { [appCodeHeader]: appCode },
    method: endpoint.method,
    query
  });
  return normalizeRechargeBillPage(data);
}

function normalizeOptions(data = {}) {
  return {
    apps: normalizeApps(data.apps),
    operations: FINANCE_OPERATIONS,
    walletIdentities: WALLET_IDENTITIES
  };
}

function normalizeApps(data) {
  return listItems(data)
    .map((item) => {
      const appCode = stringValue(item.appCode ?? item.app_code ?? item.code);
      if (!appCode) {
        return null;
      }
      return {
        appCode,
        appName: stringValue(item.appName ?? item.app_name ?? item.name) || appCode
      };
    })
    .filter(Boolean);
}

function listItems(data) {
  if (Array.isArray(data)) {
    return data;
  }
  if (Array.isArray(data?.items)) {
    return data.items;
  }
  return [];
}

function cleanRechargeBillQuery(query = {}) {
  const {
    app_code: _appCode,
    appCode: _camelAppCode,
    page: _page,
    page_size: _pageSize,
    pageSize: _camelPageSize,
    ...rest
  } = query;
  return rest;
}

function positiveInteger(value, fallback) {
  const number = Number(value);
  return Number.isInteger(number) && number > 0 ? number : fallback;
}

function stringValue(value) {
  return String(value ?? "").trim();
}
