import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
import { request } from '../request';
import {
  type ServiceRequestResult,
  mapServiceResult,
  normalizeNullableStringId,
  normalizeStringId,
  safeJsonRequestConfig
} from './shared';

const LOGIN_LOG_PREFIX = `${SYSTEM_SERVICE_PREFIX}/login-log`;
const OPERATE_LOG_PREFIX = `${SYSTEM_SERVICE_PREFIX}/operate-log`;
const API_ACCESS_LOG_PREFIX = `${SYSTEM_SERVICE_PREFIX}/api-access-log`;
const API_ERROR_LOG_PREFIX = `${SYSTEM_SERVICE_PREFIX}/api-error-log`;

type StringIdResponse = string | number;

type LoginLogResponse = Omit<Api.SystemLog.Login.Log, 'id' | 'userId'> & {
  id: StringIdResponse;
  userId?: StringIdResponse | null;
};

type OperateLogResponse = Omit<Api.SystemLog.Operate.Log, 'id' | 'userId' | 'bizId'> & {
  id: StringIdResponse;
  userId: StringIdResponse;
  bizId?: StringIdResponse | null;
};

type ApiAccessLogResponse = Omit<Api.SystemLog.ApiAccess.Log, 'id' | 'userId'> & {
  id: StringIdResponse;
  userId: StringIdResponse;
};

type ApiErrorLogResponse = Omit<Api.SystemLog.ApiError.Log, 'id' | 'userId' | 'processUserId'> & {
  id: StringIdResponse;
  userId: StringIdResponse;
  processUserId?: StringIdResponse | null;
};

type LoginLogPageResponse = Api.SystemLog.Common.PageResult<LoginLogResponse>;
type OperateLogPageResponse = Api.SystemLog.Common.PageResult<OperateLogResponse>;
type ApiAccessLogPageResponse = Api.SystemLog.Common.PageResult<ApiAccessLogResponse>;
type ApiErrorLogPageResponse = Api.SystemLog.Common.PageResult<ApiErrorLogResponse>;

function appendValue(query: URLSearchParams, key: string, value: unknown) {
  if (value === null || value === undefined || value === '') return;

  if (Array.isArray(value)) {
    value.forEach(item => appendValue(query, key, item));
    return;
  }

  query.append(key, String(value));
}

function buildQuery(params: Record<string, unknown> = {}) {
  const query = new URLSearchParams();

  Object.entries(params).forEach(([key, value]) => {
    appendValue(query, key, value);
  });

  return query.toString();
}

function normalizeLoginLog(log: LoginLogResponse): Api.SystemLog.Login.Log {
  return {
    ...log,
    id: normalizeStringId(log.id),
    userId: normalizeNullableStringId(log.userId),
    traceId: log.traceId ?? null,
    userType: log.userType ?? null,
    userAgent: log.userAgent ?? null
  };
}

function normalizeOperateLog(log: OperateLogResponse): Api.SystemLog.Operate.Log {
  return {
    ...log,
    id: normalizeStringId(log.id),
    userId: normalizeStringId(log.userId),
    bizId: normalizeNullableStringId(log.bizId),
    traceId: log.traceId ?? null,
    action: log.action ?? null,
    extra: log.extra ?? null
  };
}

function normalizeApiAccessLog(log: ApiAccessLogResponse): Api.SystemLog.ApiAccess.Log {
  return {
    ...log,
    id: normalizeStringId(log.id),
    userId: normalizeStringId(log.userId),
    traceId: log.traceId ?? null,
    requestParams: log.requestParams ?? null,
    responseBody: log.responseBody ?? null,
    operateModule: log.operateModule ?? null,
    operateName: log.operateName ?? null,
    operateType: log.operateType ?? null,
    resultMsg: log.resultMsg ?? null
  };
}

function normalizeApiErrorLog(log: ApiErrorLogResponse): Api.SystemLog.ApiError.Log {
  return {
    ...log,
    id: normalizeStringId(log.id),
    userId: normalizeStringId(log.userId),
    traceId: log.traceId ?? null,
    requestParams: log.requestParams ?? null,
    exceptionRootCauseMessage: log.exceptionRootCauseMessage ?? null,
    exceptionStackTrace: log.exceptionStackTrace ?? null,
    exceptionClassName: log.exceptionClassName ?? null,
    exceptionFileName: log.exceptionFileName ?? null,
    exceptionMethodName: log.exceptionMethodName ?? null,
    exceptionLineNumber: log.exceptionLineNumber ?? null,
    processTime: log.processTime ?? null,
    processUserId: normalizeNullableStringId(log.processUserId)
  };
}

export async function fetchGetLoginLogPage(params?: Api.SystemLog.Login.SearchParams) {
  const query = buildQuery((params ?? {}) as Record<string, unknown>);
  const result = await request<LoginLogPageResponse>({
    ...safeJsonRequestConfig,
    url: query ? `${LOGIN_LOG_PREFIX}/page?${query}` : `${LOGIN_LOG_PREFIX}/page`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<LoginLogPageResponse>, data => ({
    ...data,
    list: data.list.map(normalizeLoginLog)
  }));
}

export async function fetchGetLoginLog(id: string) {
  const result = await request<LoginLogResponse>({
    ...safeJsonRequestConfig,
    url: `${LOGIN_LOG_PREFIX}/get`,
    method: 'get',
    params: { id }
  });

  return mapServiceResult(result as ServiceRequestResult<LoginLogResponse>, normalizeLoginLog);
}

export function fetchExportLoginLog(params: Api.SystemLog.Login.SearchParams = {}) {
  const query = buildQuery(params as Record<string, unknown>);

  return request<Blob, 'blob'>({
    url: query ? `${LOGIN_LOG_PREFIX}/export-excel?${query}` : `${LOGIN_LOG_PREFIX}/export-excel`,
    method: 'get',
    responseType: 'blob'
  });
}

export async function fetchGetOperateLogPage(params?: Api.SystemLog.Operate.SearchParams) {
  const query = buildQuery((params ?? {}) as Record<string, unknown>);
  const result = await request<OperateLogPageResponse>({
    ...safeJsonRequestConfig,
    url: query ? `${OPERATE_LOG_PREFIX}/page?${query}` : `${OPERATE_LOG_PREFIX}/page`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<OperateLogPageResponse>, data => ({
    ...data,
    list: data.list.map(normalizeOperateLog)
  }));
}

export async function fetchGetOperateLog(id: string) {
  const result = await request<OperateLogResponse>({
    ...safeJsonRequestConfig,
    url: `${OPERATE_LOG_PREFIX}/get`,
    method: 'get',
    params: { id }
  });

  return mapServiceResult(result as ServiceRequestResult<OperateLogResponse>, normalizeOperateLog);
}

export function fetchExportOperateLog(params: Api.SystemLog.Operate.SearchParams = {}) {
  const query = buildQuery(params as Record<string, unknown>);

  return request<Blob, 'blob'>({
    url: query ? `${OPERATE_LOG_PREFIX}/export-excel?${query}` : `${OPERATE_LOG_PREFIX}/export-excel`,
    method: 'get',
    responseType: 'blob'
  });
}

export async function fetchGetApiAccessLogPage(params?: Api.SystemLog.ApiAccess.SearchParams) {
  const query = buildQuery((params ?? {}) as Record<string, unknown>);
  const result = await request<ApiAccessLogPageResponse>({
    ...safeJsonRequestConfig,
    url: query ? `${API_ACCESS_LOG_PREFIX}/page?${query}` : `${API_ACCESS_LOG_PREFIX}/page`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<ApiAccessLogPageResponse>, data => ({
    ...data,
    list: data.list.map(normalizeApiAccessLog)
  }));
}

export async function fetchGetApiAccessLog(id: string) {
  const result = await request<ApiAccessLogResponse>({
    ...safeJsonRequestConfig,
    url: `${API_ACCESS_LOG_PREFIX}/get`,
    method: 'get',
    params: { id }
  });

  return mapServiceResult(result as ServiceRequestResult<ApiAccessLogResponse>, normalizeApiAccessLog);
}

export function fetchExportApiAccessLog(params: Api.SystemLog.ApiAccess.SearchParams = {}) {
  const query = buildQuery(params as Record<string, unknown>);

  return request<Blob, 'blob'>({
    url: query ? `${API_ACCESS_LOG_PREFIX}/export-excel?${query}` : `${API_ACCESS_LOG_PREFIX}/export-excel`,
    method: 'get',
    responseType: 'blob'
  });
}

export async function fetchGetApiErrorLogPage(params?: Api.SystemLog.ApiError.SearchParams) {
  const query = buildQuery((params ?? {}) as Record<string, unknown>);
  const result = await request<ApiErrorLogPageResponse>({
    ...safeJsonRequestConfig,
    url: query ? `${API_ERROR_LOG_PREFIX}/page?${query}` : `${API_ERROR_LOG_PREFIX}/page`,
    method: 'get'
  });

  return mapServiceResult(result as ServiceRequestResult<ApiErrorLogPageResponse>, data => ({
    ...data,
    list: data.list.map(normalizeApiErrorLog)
  }));
}

export async function fetchGetApiErrorLog(id: string) {
  const result = await request<ApiErrorLogResponse>({
    ...safeJsonRequestConfig,
    url: `${API_ERROR_LOG_PREFIX}/get`,
    method: 'get',
    params: { id }
  });

  return mapServiceResult(result as ServiceRequestResult<ApiErrorLogResponse>, normalizeApiErrorLog);
}

export function fetchExportApiErrorLog(params: Api.SystemLog.ApiError.SearchParams = {}) {
  const query = buildQuery(params as Record<string, unknown>);

  return request<Blob, 'blob'>({
    url: query ? `${API_ERROR_LOG_PREFIX}/export-excel?${query}` : `${API_ERROR_LOG_PREFIX}/export-excel`,
    method: 'get',
    responseType: 'blob'
  });
}
