import { env } from "cloudflare:workers";
import { Cause, Effect } from "effect";
import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
import { autumnHandler } from "autumn-js/backend";

import { WorkOSClient } from "../../auth/workos";
import { ORG_SELECTOR_HEADER, authorizeOrganizationSelector } from "../../auth/organization";
import {
  HttpResponseError,
  isServerError,
  toErrorServerResponseEffect,
} from "../../api/error-response";

type BillingSession = {
  readonly userId: string;
  readonly organizationId?: string | null;
};

export const resolveBillingOrganization = (request: Request, session: BillingSession) =>
  Effect.gen(function* () {
    const selector = request.headers.get(ORG_SELECTOR_HEADER) ?? session.organizationId;
    if (!selector) {
      return yield* new HttpResponseError({
        status: 401,
        code: "unauthorized",
        message: "Unauthorized",
      });
    }

    const org = yield* authorizeOrganizationSelector(session.userId, selector);
    if (!org) {
      return yield* new HttpResponseError({
        status: 403,
        code: "forbidden",
        message: "Forbidden",
      });
    }
    return org;
  });

const handler = Effect.gen(function* () {
  const request = yield* HttpServerRequest.HttpServerRequest;
  const webRequest = yield* Effect.mapError(
    HttpServerRequest.toWeb(request),
    () =>
      new HttpResponseError({
        status: 500,
        code: "invalid_request",
        message: "Invalid request",
      }),
  );

  const workos = yield* WorkOSClient;
  const session = yield* workos.authenticateRequest(webRequest);

  if (!session) {
    return yield* new HttpResponseError({
      status: 401,
      code: "unauthorized",
      message: "Unauthorized",
    });
  }
  const org = yield* resolveBillingOrganization(webRequest, session);

  const url = new URL(webRequest.url);
  const body =
    request.method !== "GET" && request.method !== "HEAD"
      ? yield* Effect.mapError(
          request.json,
          () =>
            new HttpResponseError({
              status: 400,
              code: "invalid_json",
              message: "Invalid request body",
            }),
        )
      : undefined;

  const { statusCode, response } = yield* Effect.promise(() =>
    autumnHandler({
      request: {
        url: url.pathname,
        method: request.method,
        body,
      },
      customerId: org.id,
      customerData: {
        name: session.email,
        email: session.email,
      },
      clientOptions: {
        secretKey: env.AUTUMN_SECRET_KEY ?? "",
        // autumn-js's handler reads `baseURL` to override the Autumn endpoint
        // (not `serverURL`, which it silently ignores). Without this, a non-prod
        // AUTUMN_API_URL (the e2e emulator, a self-hosted Autumn) is dropped and
        // every billing request goes to production Autumn and 401s.
        ...(env.AUTUMN_API_URL ? { baseURL: env.AUTUMN_API_URL } : {}),
      },
      pathPrefix: "/api/billing",
    }),
  );

  if (statusCode >= 400) {
    console.error("[autumn] upstream error:", statusCode, response);
    return yield* new HttpResponseError({
      status: statusCode,
      code: "billing_request_failed",
      message: "Billing request failed",
    });
  }

  return HttpServerResponse.jsonUnsafe(response, { status: statusCode });
}).pipe(
  Effect.catchCause((err) => {
    if (isServerError(err)) {
      console.error("[autumn] request failed:", Cause.pretty(err));
    }
    return toErrorServerResponseEffect(err);
  }),
);

export const AutumnRoutesLive = HttpRouter.add("*", "/api/billing/*", handler);
