import { Order } from "./orderModel.js";
const { PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET } = process.env;
const base = "https://api-m.sandbox.paypal.com";
import axios from "axios";
import mongoose from "mongoose";
import ShippingAddress from "../ShippingAddresses/ShippingAddressModel.js";
//paypal client id get
export const getClientId = async (req, res) => {
  try {
    res.status(200).json({
      success: true,
      clientId: PAYPAL_CLIENT_ID,
    });
  } catch (error) {
    res.status(500).json({
      success: false,
      message: error.message ? error.message : "Something went Wrong",
    });
  }
};
//generate unique order id
const generateOrderId = async () => {
  const currentYear = new Date().getFullYear();
  // Find the latest order to get the last serial number
  const latestOrder = await Order.findOne({}, {}, { sort: { orderID: -1 } });
  let serialNumber = 1;

  if (latestOrder) {
    const lastYear = parseInt(latestOrder.orderID.substring(0, 4), 10);
    if (lastYear === currentYear) {
      // If the last order was in the current year, increment the serial number
      serialNumber = parseInt(latestOrder.orderID.substring(4), 10) + 1;
    }
  }
  // Pad the serial number with zeros and concatenate with the current year
  const paddedSerialNumber = serialNumber.toString().padStart(7, "0");
  const orderId = `${currentYear}${paddedSerialNumber}`;
  return orderId;
};

//* Generate an OAuth 2.0 access token for authenticating with PayPal REST APIs.
//  https://developer.paypal.com/api/rest/authentication/
//  */
const generateAccessToken = async () => {
  const credentials = `${PAYPAL_CLIENT_ID}:${PAYPAL_CLIENT_SECRET}`;
  const base64Credentials = Buffer.from(credentials).toString("base64");

  const headers = {
    "Content-Type": "application/x-www-form-urlencoded",
    Authorization: `Basic ${base64Credentials}`,
  };

  const data = "grant_type=client_credentials";

  try {
    const response = await axios.post(`${base}/v1/oauth2/token`, data, {
      headers: headers,
    });
    // console.log("response.data", response.data);
    const accessToken = response.data?.access_token;
    return accessToken;
  } catch (error) {
    console.error(
      "Error getting access token:",
      error.response ? error.response.data : error.message
    );
  }
};

const handleResponse = async (response) => {
  try {
    if (response.status >= 200 && response.status < 300) {
      return {
        success: true,
        responseData: response.data,
        httpStatusCode: response.status,
      };
    }
  } catch (err) {
    const errorMessage = await response.statusText;
    throw new Error(errorMessage);
  }
};

// https://developer.paypal.com/docs/api/orders/v2/#orders_create

export const createOrderCheckout = async (req, res) => {
  try {
    const { address, cart, subtotal } = req.body;
    if (cart.length < 1)
      return res.status(400).json({ message: "cart is empty!" });
    switch (true) {
      //validation
      case !address: {
        return res.status(404).json({ msg: "please provide shipping address" });
      }
      case !subtotal: {
        return res.status(404).json({ msg: "please provide product subtotal" });
      }
    }
    const orderItems = await cart.map((item) => ({
      product: item.product._id,
      name: item.product.name,
      price: item.product.price,
      image: item.product.image,
      quantity: item.quantity,
      product_subtotal: item.subtotal,
      price_With_Tax: 0,
      taxId: "",
    }));
    let addss = await ShippingAddress.findById(address);
    let shipping = {
      Name: addss.Name,
      phoneNumber: addss.phoneNumber,
      street: addss.street,
      city: addss.city,
      state: addss.state,
      panpanNumber: addss.panNumber,
      postalCode: addss?.postalCode,
      country: addss.country,
      addressId: address,
    };
    req.body.user = req.user._id;
    const Id = await generateOrderId();
    const order = await Order.create({
      orderID: Id,
      total_amount: subtotal,
      orderItems,
      shippingInfo: shipping,
      user: req.user._id,
    });
    if (order) {
      const accessToken = await generateAccessToken();
      const url = `${base}/v2/checkout/orders`;
      const createOrderRequest = {
        intent: "CAPTURE",
        purchase_units: [
          {
            amount: {
              currency_code: "USD",
              value: subtotal, //"60.00" Replace with the actual amount
              //optional product product total value
              // breakdown: {
              //   item_total: {
              //     currency_code: "USD",
              //     value: "60.00", // Replace with the total value of all items
              //   },
              // },
            },
            //optional give product product also show in paypal dashboard
            // items: [
            //   {
            //     name: "Apple",
            //     unit_amount: {
            //       currency_code: "USD",
            //       value: "60.00", // Replace with the actual item price
            //     },
            //     quantity: 1,
            //   },
            // ],
          },
        ],
      };
      const response = await axios.post(
        url,
        JSON.stringify(createOrderRequest),
        {
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${accessToken}`,
          },
        }
      );

      if (response.status >= 200 && response.status < 300) {
        let paymentOrderId = await Order.findById(order?._id);
        paymentOrderId.paypal_payment_id = response.data?.id;
        await paymentOrderId.save();
        return res.status(201).json({
          success: true,
          responseData: response.data,
          product_orderId: order?._id,
          httpStatusCode: response.status,
        });
      } else {
        // Handle errors or unexpected status codes
        console.error("Error:", response.status, response.statusText);

        //  Optionally, you can parse the error response as JSON if available
        try {
          const errorData = response.data;
          console.error("Error Data:", errorData);
        } catch (error) {
          console.error("Error parsing error data:", error.message);
        }
      }
    }
  } catch (error) {
    const errorMessage = await error.message;
    return res.status(500).json({
      success: false,
      message: errorMessage,
    });
  }
};

/**
 * Capture payment for the created order to complete the transaction.
 * //see https://developer.paypal.com/docs/api/orders/v2/#orders_capture
 */

const captureOrder = async (orderID) => {
  const accessToken = await generateAccessToken();
  const url = `${base}/v2/checkout/orders/${orderID}/capture`;
  const response = await axios.post(
    url,
    {},
    {
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${accessToken}`,
        // Uncomment one of these to force an error for negative testing (in sandbox mode only). Documentation:
        // https://developer.paypal.com/tools/sandbox/negative-testing/request-headers/
        // "PayPal-Mock-Response": '{"mock_application_codes": "INSTRUMENT_DECLINED"}'
        // "PayPal-Mock-Response": '{"mock_application_codes": "TRANSACTION_REFUSED"}'
        // "PayPal-Mock-Response": '{"mock_application_codes": "INTERNAL_SERVER_ERROR"}'
      },
    }
  );
  return handleResponse(response);
};

export const captureOrderPayment = async (req, res) => {
  try {
    const { orderID } = req.params;

    const { responseData, httpStatusCode } = await captureOrder(orderID);
    const payment = await Order.findOne({
      paypal_payment_id: responseData?.id,
    });
    // Handle different transaction statuses
    if (responseData?.status === "COMPLETED") {
      payment.paypal_payer_id = responseData.payer?.payer_id;
      payment.paidAt = Date.now();
      payment.isPaid = true;
      payment.payment_status = "success";
      payment.orderStatus = "new";
      await payment.save();
    } else if (responseData?.status === "PENDING") {
      console.log("Payment is pending.");
      payment.paypal_payer_id = responseData.payer?.payer_id;
      payment.paidAt = Date.now();
      payment.payment_status = "pending";
      await payment.save();
    } else if (responseData?.status === "FAILED") {
      payment.paypal_payer_id = responseData.payer?.payer_id;
      payment.paidAt = Date.now();
      payment.payment_status = "failed";
      await payment.save();
    }

    return res.status(httpStatusCode).json(responseData);
  } catch (error) {
    // console.error("Failed to create order:", error);
    res
      .status(500)
      .json({ message: error.message || "Failed to capture order." });
  }
};
