import { sepahBrokerClients } from "$clients/index.js";
import { servicesConfig } from "$config/index.js";

const buildBaseHeaders = () => ({
  UserName: servicesConfig.sepahBrokerConfig.username,
  Password: servicesConfig.sepahBrokerConfig.password,
  TokenID: servicesConfig.sepahBrokerConfig.tokenId,
});

const buildOtpHeaders = (otpCode) => ({
  ...buildBaseHeaders(),
  OTPCode: String(otpCode),
});

const normalizeIdentifier = (identifier) => String(identifier || "").trim();

const assertRequiredValue = (value, fieldName, message) => {
  if (value === undefined || value === null || value === "") {
    const error = new Error(message || `${fieldName} is required.`);
    error.status = 422;
    throw error;
  }

  return value;
};

const extractOtpCode = (payload) => {
  const candidates = [
    payload?.OTPCode,
    payload?.otpCode,
    payload?.OtpCode,
    payload?.data?.OTPCode,
    payload?.data?.otpCode,
    payload?.data?.OtpCode,
    payload?.result?.OTPCode,
    payload?.result?.otpCode,
    payload?.result?.OtpCode,
    payload?.Data?.OTPCode,
    payload?.Data?.otpCode,
    payload?.Data?.OtpCode,
  ];

  for (const candidate of candidates) {
    if (candidate !== undefined && candidate !== null && candidate !== "") {
      return String(candidate).trim();
    }
  }

  if (typeof payload === "string" || typeof payload === "number") {
    return String(payload).trim();
  }

  return null;
};

const createServiceError = (error, fallbackMessage) => ({
  status: error?.response?.status || error?.status || 503,
  message: fallbackMessage,
  details: error?.response?.data || error?.message,
});

const requestFreshOtp = async (identifier) => {
  try {
    const normalizedIdentifier = normalizeIdentifier(
      assertRequiredValue(
        identifier,
        "identifier",
        "شناسه هویتی برای دریافت OTP الزامی است.",
      ),
    );

    const response = await sepahBrokerClients.otp.request({
      method: "GET",
      url: "",
      headers: buildBaseHeaders(),
      data: {
        NationalNo: normalizedIdentifier,
      },
    });

    const otpCode = extractOtpCode(response?.data);

    if (!otpCode) {
      throw new Error("No OTP code received from Sepah broker.");
    }

    return otpCode;
  } catch (error) {
    console.error("❌ Error getting Sepah broker OTP:", error?.message);
    throw createServiceError(error, "خطا در دریافت کد OTP کارگزاری سپه");
  }
};

const withFreshOtp = async (identifier, callback) => {
  const otpCode = await requestFreshOtp(identifier);
  return callback(otpCode);
};

const resolveTradeCode = ({ tradeCode, identifier }) =>
  normalizeIdentifier(
    assertRequiredValue(
      tradeCode || identifier,
      "tradeCode",
      "TradeCode مشتری برای کارگزاری سپه الزامی است.",
    ),
  );

export const requestOtp = async (identifier) => requestFreshOtp(identifier);

export const getCustomerByNationalCode = async (nationalCode) => {
  const normalizedNationalCode = normalizeIdentifier(
    assertRequiredValue(
      nationalCode,
      "nationalCode",
      "شناسه هویتی مشتری الزامی است.",
    ),
  );

  try {
    return await withFreshOtp(normalizedNationalCode, async (otpCode) => {
      const response = await sepahBrokerClients.services.get(
        "/GetCustomerByNationalCode",
        {
          params: { nationalNo: normalizedNationalCode },
          headers: buildOtpHeaders(otpCode),
        },
      );

      return response.data;
    });
  } catch (error) {
    if (error?.message === "خطا در دریافت کد OTP کارگزاری سپه") {
      throw error;
    }

    console.error("❌ Error getting Sepah broker customer:", error?.message);
    throw createServiceError(error, "خطا در دریافت اطلاعات مشتری از کارگزاری سپه");
  }
};

export const getCustomerRemain = async (
  nationalIdentification,
  market = servicesConfig.sepahBrokerConfig.defaultMarket,
) => {
  const normalizedNationalCode = normalizeIdentifier(
    assertRequiredValue(
      nationalIdentification,
      "nationalIdentification",
      "شناسه هویتی مشتری الزامی است.",
    ),
  );

  try {
    return await withFreshOtp(normalizedNationalCode, async (otpCode) => {
      const response = await sepahBrokerClients.services.get("/GetCustomerRemain", {
        params: {
          nationalIdentification: normalizedNationalCode,
          market,
        },
        headers: buildOtpHeaders(otpCode),
      });

      return response.data;
    });
  } catch (error) {
    if (error?.message === "خطا در دریافت کد OTP کارگزاری سپه") {
      throw error;
    }

    console.error("❌ Error getting Sepah broker remain:", error?.message);
    throw createServiceError(error, "خطا در دریافت مانده مشتری از کارگزاری سپه");
  }
};

export const getCustomerPortfolio = async (nationalID, fundRef) => {
  const normalizedNationalCode = normalizeIdentifier(
    assertRequiredValue(
      nationalID,
      "nationalID",
      "شناسه هویتی مشتری الزامی است.",
    ),
  );

  try {
    return await withFreshOtp(normalizedNationalCode, async (otpCode) => {
      const response = await sepahBrokerClients.services.get(
        "/GetCustomerPortfolio",
        {
          params: {
            nationalID: normalizedNationalCode,
            FundRef: assertRequiredValue(
              fundRef,
              "fundRef",
              "شناسه صندوق الزامی است.",
            ),
          },
          headers: buildOtpHeaders(otpCode),
        },
      );

      return response.data;
    });
  } catch (error) {
    if (error?.message === "خطا در دریافت کد OTP کارگزاری سپه") {
      throw error;
    }

    console.error("❌ Error getting Sepah broker portfolio:", error?.message);
    throw createServiceError(error, "خطا در دریافت پرتفوی مشتری از کارگزاری سپه");
  }
};

export const addSellOfflineOrder = async ({
  identifier,
  nationalCode,
  quantity,
  dateCondition,
  tradeCode,
  fundRef,
}) => {
  const normalizedIdentifier = normalizeIdentifier(
    assertRequiredValue(
      identifier || nationalCode,
      "identifier",
      "شناسه هویتی مشتری الزامی است.",
    ),
  );

  try {
    const resolvedTradeCode = resolveTradeCode({
      identifier: normalizedIdentifier,
      tradeCode,
    });

    return await withFreshOtp(normalizedIdentifier, async (otpCode) => {
      const response = await sepahBrokerClients.services.post(
        "/AddSellOfflineOrder",
        {
          Quantity: assertRequiredValue(
            quantity,
            "quantity",
            "تعداد واحد فروش الزامی است.",
          ),
          DateCondition: assertRequiredValue(
            dateCondition,
            "dateCondition",
            "تاریخ درخواست الزامی است.",
          ),
          TradeCode: resolvedTradeCode,
          FundRef: assertRequiredValue(
            fundRef,
            "fundRef",
            "شناسه صندوق الزامی است.",
          ),
        },
        {
          headers: buildOtpHeaders(otpCode),
        },
      );

      return response.data;
    });
  } catch (error) {
    if (error?.message === "خطا در دریافت کد OTP کارگزاری سپه") {
      throw error;
    }

    console.error("❌ Error adding Sepah broker sell order:", error?.message);
    throw createServiceError(error, "خطا در ثبت درخواست فروش کارگزاری سپه");
  }
};

export const addBuyOfflineOrder = async ({
  identifier,
  nationalCode,
  amount,
  dateCondition,
  tradeCode,
  fundRef,
}) => {
  const normalizedIdentifier = normalizeIdentifier(
    assertRequiredValue(
      identifier || nationalCode,
      "identifier",
      "شناسه هویتی مشتری الزامی است.",
    ),
  );

  try {
    const resolvedTradeCode = resolveTradeCode({
      identifier: normalizedIdentifier,
      tradeCode,
    });

    return await withFreshOtp(normalizedIdentifier, async (otpCode) => {
      const response = await sepahBrokerClients.services.post(
        "/AddBuyOfflineOrder",
        {
          Amount: assertRequiredValue(amount, "amount", "مبلغ خرید الزامی است."),
          DateCondition: assertRequiredValue(
            dateCondition,
            "dateCondition",
            "تاریخ درخواست الزامی است.",
          ),
          TradeCode: resolvedTradeCode,
          FundRef: assertRequiredValue(
            fundRef,
            "fundRef",
            "شناسه صندوق الزامی است.",
          ),
        },
        {
          headers: buildOtpHeaders(otpCode),
        },
      );

      return response.data;
    });
  } catch (error) {
    if (error?.message === "خطا در دریافت کد OTP کارگزاری سپه") {
      throw error;
    }

    console.error("❌ Error adding Sepah broker buy order:", error?.message);
    throw createServiceError(error, "خطا در ثبت درخواست خرید کارگزاری سپه");
  }
};

export const createPaymentRequest = async ({
  nationalId,
  identifier,
  amount,
  description,
  requestNumber,
  mobileNumber,
  fundRef,
  callBackUrl,
}) => {
  const normalizedNationalCode = normalizeIdentifier(
    assertRequiredValue(
      nationalId || identifier,
      "nationalId",
      "شناسه هویتی مشتری الزامی است.",
    ),
  );

  try {
    return await withFreshOtp(normalizedNationalCode, async (otpCode) => {
      const response = await sepahBrokerClients.gateway.post(
        "/PayRequest",
        {
          amount: assertRequiredValue(amount, "amount", "مبلغ پرداخت الزامی است."),
          description: assertRequiredValue(
            description,
            "description",
            "شرح پرداخت الزامی است.",
          ),
          requestNumber: assertRequiredValue(
            requestNumber,
            "requestNumber",
            "شماره درخواست الزامی است.",
          ),
          mobileNumber: assertRequiredValue(
            mobileNumber,
            "mobileNumber",
            "شماره موبایل الزامی است.",
          ),
          nationalId: normalizedNationalCode,
          FundRef: assertRequiredValue(
            fundRef,
            "fundRef",
            "شناسه صندوق الزامی است.",
          ),
          callBackUrl: assertRequiredValue(
            callBackUrl,
            "callBackUrl",
            "آدرس بازگشت الزامی است.",
          ),
        },
        {
          headers: buildOtpHeaders(otpCode),
        },
      );

      return response.data;
    });
  } catch (error) {
    if (error?.message === "خطا در دریافت کد OTP کارگزاری سپه") {
      throw error;
    }

    console.error("❌ Error creating Sepah payment request:", error?.message);
    throw createServiceError(error, "خطا در ایجاد درخواست پرداخت کارگزاری سپه");
  }
};

export const checkPayment = async ({ nationalId, token, fundRef }) => {
  const normalizedNationalCode = normalizeIdentifier(
    assertRequiredValue(nationalId, "nationalId", "شناسه هویتی مشتری الزامی است."),
  );

  try {
    return await withFreshOtp(normalizedNationalCode, async (otpCode) => {
      const response = await sepahBrokerClients.gateway.post(
        "/CheckPay",
        {
          token: assertRequiredValue(token, "token", "توکن پرداخت الزامی است."),
          FundRef: assertRequiredValue(
            fundRef,
            "fundRef",
            "شناسه صندوق الزامی است.",
          ),
        },
        {
          headers: buildOtpHeaders(otpCode),
        },
      );

      return response.data;
    });
  } catch (error) {
    if (error?.message === "خطا در دریافت کد OTP کارگزاری سپه") {
      throw error;
    }

    console.error("❌ Error checking Sepah payment:", error?.message);
    throw createServiceError(error, "خطا در تایید پرداخت کارگزاری سپه");
  }
};
