import { logger } from "../../logger";
import { ErrorType, ServerError, ServerResult } from "../types";
import { getRequest } from "@tanstack/react-start/server";
import { isRedirect } from "@tanstack/react-router";

export const createServerError = (
  type: ErrorType,
  message: string,
  userMessage: string,
  statusCode?: number,
  context?: Record<string, any>
): ServerError => ({
  code: type,
  message,
  userMessage,
  statusCode,
  context,
});

export const toServerResult = async <T>(
  serverFn: () => Promise<T>
): Promise<ServerResult<T>> => {
  const startTime = Date.now();

  try {
    const data = await serverFn();
    return { success: true, data };
  } catch (error) {
    if (isRedirect(error) || error instanceof Response) throw error;

    const duration = Date.now() - startTime;
    logger.error('Server Fn Error', error);

    const mappedError = mapKnownError(error);

    let fnName = 'unknown';
    try {
      const request = getRequest();
      const url = new URL(request.url);

      const functionId = url.searchParams.get('_serverFnId') || url.pathname;

      if (functionId.includes('--')) {
        const match = functionId.match(/--([^_]+)_/);
        fnName = match?.[1] || functionId.split('--')[1]?.split('_')[0] || 'unknown';
      } else {
        fnName = serverFn.name || 'unknown';
      }
    } catch {
      fnName = serverFn.name || 'unknown';
    }

    import("../../pocketbase/client")
      .then(async ({ pbAdmin }) => {
        await pbAdmin.authPromise;
        await pbAdmin.createActivity({
          name: fnName,
          duration,
          success: false,
          error: mappedError.message,
          arguments: {
            errorType: mappedError.code,
            statusCode: mappedError.statusCode,
            userMessage: mappedError.userMessage,
          },
        });
      })
      .catch(() => {});

    return { success: false, error: mappedError };
  }
};

const mapKnownError = (error: unknown): ServerError => {
  if (error && typeof error === "object" && "status" in error) {
    const pbError = error as {
      status: number;
      message: string;
      data?: unknown;
    };

    switch (pbError.status) {
      case 400:
        return createServerError(
          ErrorType.VALIDATION,
          pbError.message,
          "Invalid request",
          400,
          { originalError: pbError.data }
        );
      case 401:
        return createServerError(
          ErrorType.UNAUTHORIZED,
          pbError.message,
          "You are not authorized to perform this action",
          401
        );
      case 403:
        return createServerError(
          ErrorType.FORBIDDEN,
          pbError.message,
          "Access denied",
          403
        );
      case 404:
        return createServerError(
          ErrorType.NOT_FOUND,
          pbError.message,
          "The requested resource was not found",
          404
        );
      default:
        return createServerError(
          ErrorType.POCKETBASE,
          pbError.message,
          "Something went wrong. Please try again.",
          pbError.status
        );
    }
  }

  if (error instanceof TypeError && error.message.includes("fetch")) {
    return createServerError(
      ErrorType.NETWORK,
      error.message,
      "Network error. Please check your connection and try again."
    );
  }

  if (error instanceof Error) {
    return createServerError(
      ErrorType.UNKNOWN,
      error.message,
      "An unexpected error occurred. Please try again.",
      undefined,
      { stack: error.stack }
    );
  }

  return createServerError(
    ErrorType.UNKNOWN,
    String(error),
    "An unexpected error occurred. Please try again.",
    undefined,
    { originalError: error }
  );
};
