import {
  PaymobPaymentType,
  PaymobTransactionResponse,
} from "./../model/paymob-model";
import axios from "axios";
import * as functions from "firebase-functions";
import {
  ConfirmPayment,
  PaymentMethod,
  PaymentStatus,
  confirmPayment,
  createOrder,
} from "../payment-functions";
import * as random from "randomstring";
import {
  BookByWho,
  TimeSlotModel,
  UserModel,
  doctorCol,
  orderCol,
  timeSlotCol,
  usersCol,
} from "../collections";
import {
  PaymobOrderResponse,
  PaymobResponseFinal,
  PaymobUserTokenResponse,
} from "../model/paymob-model";
import { integrationIdCard, integrationIdKiosk } from "../constants";

export const paymobCreateOrder = functions.https.onCall(
  async (request, response) => {
    try {
      const timeSlotId = request.timeSlotId;
      const userId = request.userId;
      const paymentType: PaymobPaymentType = request.paymentType;
      // console.log("payment type : " + paymentType);
      console.log("userId : " + userId);
      console.log("timeSlotId : " + timeSlotId);
      const payMobApiKey = process.env.PAYMOB_API_KEY;
      if (payMobApiKey == undefined) {
        throw "paymob api key is undefined";
      }

      const timeSlot = (await timeSlotCol.doc(timeSlotId).get()).data();
      const user = (await usersCol.doc(userId).get()).data();
      if (user === undefined) {
        throw "user is undefined";
      }
      if (timeSlot === undefined) {
        throw "time slot is undefined";
      }
      const orderId = random.generate(12);
      const paymobResponse = await requestPaymobUserToken(payMobApiKey);
      await createOrder(request.timeSlotId, request.userId, orderId);

      const priceInCent = timeSlot.price / 10;

      if (priceInCent < 10) {
        throw "price is less than 10";
      }
      console.log("random order id : " + orderId);
      console.log("Paymob User token : " + paymobResponse.token);
      const paymobOrderData = await createOrderPaymob(
        paymobResponse.token,
        priceInCent,
        orderId,
        timeSlot,
        timeSlotId
      );
      const paymobFinalToken = await requestPaymentToken(
        paymobResponse.token,
        priceInCent,
        user,
        paymobOrderData.id.toString(),
        paymentType
      );
      if (paymentType == PaymobPaymentType.kiosk) {
        const kioskCode = await requestKioskCode(paymobFinalToken);
        return { token: paymobFinalToken, kioskCode: kioskCode };
      }
      return { token: paymobFinalToken };
    } catch (error) {
      throw error;
    }
  }
);

export const paymobPaymentWebhook = functions.https.onRequest(
  async (request, response) => {
    console.log("data : " + JSON.stringify(request.body));
    const paymobTransactionData: PaymobTransactionResponse = request.body;
    const myOrder = await orderCol
      .doc(paymobTransactionData.obj.order.merchant_order_id)
      .get();
    response.send();
    if (myOrder.data() === undefined) {
      throw "order is undefined";
    }
    const timeSlot = await timeSlotCol.doc(myOrder.data()?.timeSlotId!).get();
    const doctor = await doctorCol.doc(timeSlot.data()?.doctorId!).get();
    const user = (await usersCol.doc(myOrder.data()?.userId!).get()).data();
    const bookByWho: BookByWho = {
      displayName: user?.displayName!,
      photoUrl: "",
      userId: myOrder.data()?.userId!,
    };
    const confirmPaymentData: ConfirmPayment = {
      orderId: myOrder.id,
      timeSlotId: timeSlot.id!,
      paymentMethod: PaymentMethod.PayMob,
      paymentStatus: PaymentStatus.PaymentSuccess,
      amount: paymobTransactionData.obj.order.amount_cents,
      currency: paymobTransactionData.obj.order.currency,
      fee: paymobTransactionData.obj.order.commission_fees.toString(),
      paymentType: paymobTransactionData.obj.source_data.type,
      bookByWho: bookByWho,
      doctor: {
        doctorName: doctor.data()?.doctorName!,
        doctorPicture: doctor.data()?.doctorPicture!,
      },
      doctorId: doctor.id,
    };

    await confirmPayment(confirmPaymentData);

    console.log("payment success");
    // Send the HTML response
    response.status(200);
  }
);
export const paymobPaymentSuccessHTTPMessage = functions.https.onRequest(
  (request, response) => {
    // Set the Content-Type header to indicate that the response is HTML
    response.setHeader("Content-Type", "text/html");

    // Your HTML content
    const html = `
    <html>
    <head>
      <style>
        body {
          display: flex;
          justify-content: center;
          align-items: center;
          height: 100vh;
          margin: 0;
        }
      </style>
    </head>
    <body>
      <h1>Payment Success!</h1>
    </body>
    </html>
  `;

    // Send the HTML response
    response.status(200).send(html);
  }
);

export const requestPaymobUserToken = async (
  paymobApiKey: string
): Promise<PaymobUserTokenResponse> => {
  try {
    const requestData = {
      api_key: paymobApiKey,
    };
    const responseAxios = await axios.post(
      "https://accept.paymob.com/api/auth/tokens",
      JSON.stringify(requestData),
      {
        headers: {
          // Overwrite Axios's automatically set Content-Type
          "Content-Type": "application/json",
        },
      }
    );
    console.log("Success get user token");
    const paymobResponse: PaymobUserTokenResponse = responseAxios.data;
    return paymobResponse;
  } catch (error) {
    console.log(error);
    throw error;
  }
};

export const createOrderPaymob = async (
  token: string,
  price: number,
  orderId: string,
  timeSlot: TimeSlotModel,
  timeSlotId: string
): Promise<PaymobOrderResponse> => {
  try {
    console.log("Initiate Create Order");
    const orderReqData = {
      auth_token: token,
      delivery_needed: "false",
      amount_cents: price,
      currency: "EGP",
      merchant_order_id: orderId,
      items: [
        {
          name: "TimeSlot book " + timeSlotId,
          amount_cents: price,
          description:
            "Timeslot Booking at " + timeSlot.timeSlot.toDate().toDateString(),
          quantity: "1",
        },
      ],
    };

    console.log("orderReqData : " + JSON.stringify(orderReqData));

    const responseAxiosOrder = await axios.post(
      "https://accept.paymob.com/api/ecommerce/orders",
      JSON.stringify(orderReqData),
      {
        headers: {
          "Content-Type": "application/json",
        },
      }
    );
    console.log("Success crete order paymob");
    const paymobOrderData: PaymobOrderResponse = responseAxiosOrder.data;
    return paymobOrderData;
  } catch (error) {
    throw error;
  }
};

export const requestPaymentToken = async (
  paymobReqToken: string,
  price: number,
  user: UserModel,
  paymobOrderDataId: string,
  paymentType: PaymobPaymentType
): Promise<string> => {
  try {
    const orderReqDataFinal = {
      auth_token: paymobReqToken,
      amount_cents: price,
      expiration: 3600,
      order_id: paymobOrderDataId,
      billing_data: {
        apartment: "NA",
        email: user.email,
        floor: "NA",
        first_name: user.displayName,
        street: "NA",
        building: "NA",
        phone_number: "NA",
        shipping_method: "NA",
        postal_code: "NA",
        city: "NA",
        country: "NA",
        last_name: "NA",
        state: "NA",
      },
      currency: "EGP",
      integration_id:
        paymentType == PaymobPaymentType.card
          ? integrationIdCard
          : integrationIdKiosk,
      lock_order_when_paid: "false",
    };
    const paymobFinalCall = await axios.post(
      "https://accept.paymob.com/api/acceptance/payment_keys",
      JSON.stringify(orderReqDataFinal),
      {
        headers: {
          "Content-Type": "application/json",
        },
      }
    );
    const finalResponse: PaymobResponseFinal = paymobFinalCall.data;
    console.log("final call : " + JSON.stringify(paymobFinalCall.data));
    console.log("Success get payment token : " + finalResponse.token);

    return finalResponse.token;
  } catch (error) {
    throw error;
  }
};

export const requestKioskCode = async (finalToken: string): Promise<String> => {
  try {
    const kioskData = {
      source: {
        identifier: "AGGREGATOR",
        subtype: "AGGREGATOR",
      },
      payment_token: finalToken,
    };
    const responseAxiosKiosk = await axios.post(
      "https://accept.paymob.com/api/acceptance/payments/pay",
      JSON.stringify(kioskData),
      {
        headers: {
          "Content-Type": "application/json",
        },
      }
    );
    const kioskCodeResponse = responseAxiosKiosk.data;
    console.log("kiosk data : " + JSON.stringify(kioskCodeResponse));
    return kioskCodeResponse["id"].toString();
  } catch (e) {
    console.log(e);
    throw e;
  }
};
