import { json, type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/node";
import { v4 as uuidv4 } from "uuid";
import { authenticate, unauthenticated } from "../shopify.server";
import { runActivityCheck } from "../services/activity.server";
import { getActivityConfig } from "../services/config.server";
import { callPush, callStatus } from "../services/dreame-client.server";
import { findSuccessfulPush, recordSuccessfulPush } from "../services/idempotency.server";
import { logActivityPush } from "../services/logger.server";
import { getOrderDetails } from "../services/order.server";

const CACHE_CONTROL = "no-store, max-age=0";
const CHECKOUT_CORS_HEADERS = ["Authorization", "Content-Type"];
const FALLBACK_CORS_HEADERS = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers": "Authorization, Content-Type",
  "Access-Control-Allow-Methods": "POST, OPTIONS",
  "Cache-Control": CACHE_CONTROL,
};

type CheckoutAuthResult = Awaited<ReturnType<typeof authenticate.public.checkout>> & {
  admin?: unknown;
  session?: { shop?: string };
  shop?: string;
};

type CheckoutCors = CheckoutAuthResult["cors"];

type ActivityRequestBody = {
  orderId?: string;
  orderNumber?: string;
  locale?: string;
};

export async function loader({ request }: LoaderFunctionArgs) {
  if (request.method === "OPTIONS") {
    return handleOptions(request);
  }

  return fallbackCors(
    errorResponse("METHOD_NOT_ALLOWED", "Only POST is supported.", 405, {
      Allow: "POST",
    }),
  );
}

export async function action({ request }: ActionFunctionArgs) {
  if (request.method === "OPTIONS") {
    return handleOptions(request);
  }

  if (request.method !== "POST") {
    return fallbackCors(
      errorResponse("METHOD_NOT_ALLOWED", "Only POST is supported.", 405, {
        Allow: "POST",
      }),
    );
  }

  let authResult: CheckoutAuthResult;

  try {
    authResult = (await authenticate.public.checkout(request, {
      corsHeaders: CHECKOUT_CORS_HEADERS,
    })) as CheckoutAuthResult;
  } catch (error) {
    return authErrorResponse(error);
  }

  const { cors, sessionToken } = authResult;
  const shop = normalizeShopDomain(authResult.shop || authResult.session?.shop || sessionToken.dest);
  if (!shop) {
    return checkoutCors(
      cors,
      errorResponse("INVALID_SHOP_CONTEXT", "A valid Shopify shop context is required.", 401),
    );
  }

  const body = await parseJsonBody(request);
  if (!body) {
    return checkoutCors(cors, errorResponse("INVALID_JSON", "Request body must be valid JSON.", 400));
  }

  if (typeof body.orderId !== "string" || body.orderId.trim() === "") {
    return checkoutCors(cors, errorResponse("ORDER_ID_REQUIRED", "orderId is required.", 400));
  }

  try {
    const adminResult = authResult.admin ? { admin: authResult.admin } : shop ? await unauthenticated.admin(shop) : null;
    const admin = adminResult?.admin as {
      graphql: (query: string, options?: { variables?: Record<string, unknown> }) => Promise<Response>;
    };
    if (!shop || !admin) {
      throw new Error("Invalid Shopify checkout session");
    }

    const result = await runActivityCheck(
      {
        shop,
        orderId: body.orderId.trim(),
        orderNumber: body.orderNumber,
        locale: body.locale,
      },
      {
        nowMs: () => Date.now(),
        uuid: uuidv4,
        getOrder: (_shop, orderId) => getOrderDetails(admin, orderId),
        getConfig: () => getActivityConfig(admin),
        findSuccess: findSuccessfulPush,
        recordSuccess: recordSuccessfulPush,
        log: logActivityPush,
        callStatus,
        callPush,
      },
    );

    return checkoutCors(cors, json(result, { headers: noStoreHeaders() }));
  } catch {
    return checkoutCors(cors, errorResponse("ACTIVITY_CHECK_FAILED", "Activity check failed.", 500));
  }
}

async function handleOptions(request: Request): Promise<Response> {
  try {
    const { cors } = await authenticate.public.checkout(request, {
      corsHeaders: CHECKOUT_CORS_HEADERS,
    });
    return checkoutCors(cors, new Response(null, { status: 204, headers: noStoreHeaders() }));
  } catch (error) {
    return authErrorResponse(error);
  }
}

async function parseJsonBody(request: Request): Promise<ActivityRequestBody | null> {
  try {
    return (await request.json()) as ActivityRequestBody;
  } catch {
    return null;
  }
}

function normalizeShopDomain(value: unknown): string | null {
  if (typeof value !== "string" || value.trim() === "") {
    return null;
  }

  try {
    const url = value.includes("://") ? value : `https://${value}`;
    const hostname = new URL(url).hostname.toLowerCase();
    return hostname.endsWith(".myshopify.com") ? hostname : null;
  } catch {
    return null;
  }
}

function errorResponse(code: string, message: string, status: number, headers: HeadersInit = {}): Response {
  return json(
    {
      success: false,
      error: {
        code,
        message,
      },
    },
    {
      status,
      headers: {
        ...headers,
        ...noStoreHeaders(),
      },
    },
  );
}

function authErrorResponse(error: unknown): Response {
  if (error instanceof Response) {
    return fallbackCors(withNoStore(error));
  }

  return fallbackCors(errorResponse("CHECKOUT_AUTHENTICATION_FAILED", "Checkout authentication failed.", 401));
}

function checkoutCors(cors: CheckoutCors, response: Response): Response {
  return cors(withNoStore(response));
}

function fallbackCors(response: Response): Response {
  for (const [key, value] of Object.entries(FALLBACK_CORS_HEADERS)) {
    response.headers.set(key, value);
  }
  return response;
}

function withNoStore(response: Response): Response {
  response.headers.set("Cache-Control", CACHE_CONTROL);
  return response;
}

function noStoreHeaders(): HeadersInit {
  return {
    "Cache-Control": CACHE_CONTROL,
  };
}
