
import { router, protectedProcedure } from '@/src/trpc/trpc-index'
import { z } from 'zod'
import { ApiError } from '@/src/lib/api-error'
import { getRazorpayId, getRazorpaySecret } from "@/src/lib/env-exporter"
import { RazorpayPaymentService } from "@/src/lib/payments-utils"
import {
  getUserPaymentOrderById as getUserPaymentOrderByIdInDb,
  getUserPaymentByOrderId as getUserPaymentByOrderIdInDb,
  getUserPaymentByMerchantOrderId as getUserPaymentByMerchantOrderIdInDb,
  updateUserPaymentSuccess as updateUserPaymentSuccessInDb,
  updateUserOrderPaymentStatus as updateUserOrderPaymentStatusInDb,
  markUserPaymentFailed as markUserPaymentFailedInDb,
} from '@/src/dbService'
import type {
  UserPaymentOrderResponse,
  UserPaymentVerifyResponse,
  UserPaymentFailResponse,
} from '@packages/shared'




export const paymentRouter = router({
  createRazorpayOrder: protectedProcedure //either create a new payment order or return the existing one
    .input(z.object({
      orderId: z.string(),
    }))
    .mutation(async ({ input, ctx }): Promise<UserPaymentOrderResponse> => {
      const userId = ctx.user.userId;
      const { orderId } = input;

      const order = await getUserPaymentOrderByIdInDb(parseInt(orderId))

      /*
      // Old implementation - direct DB queries:
      const order = await db.query.orders.findFirst({
        where: eq(orders.id, parseInt(orderId)),
      });
      */

      if (!order) {
        throw new ApiError("Order not found", 404)
      }

       if (order.userId !== userId) {
         throw new ApiError("Order does not belong to user", 403)
       }

       // Check for existing pending payment
       const existingPayment = await getUserPaymentByOrderIdInDb(parseInt(orderId))

       /*
       // Old implementation - direct DB queries:
       const existingPayment = await db.query.payments.findFirst({
         where: eq(payments.orderId, parseInt(orderId)),
       });
       */

       if (existingPayment && existingPayment.status === 'pending') {
         return {
            razorpayOrderId: existingPayment.merchantOrderId,
            key: getRazorpayId(),
         };
       }

          // Create Razorpay order and insert payment record
           if (order.totalAmount === null) {
             throw new ApiError('Order total is missing', 400)
           }
           const razorpayOrder = await RazorpayPaymentService.createOrder(parseInt(orderId), order.totalAmount);
           await RazorpayPaymentService.insertPaymentRecord(parseInt(orderId), razorpayOrder);

        return {
          razorpayOrderId: 0,
          key: getRazorpayId(),
        }
    }),



  verifyPayment: protectedProcedure
    .input(z.object({
      razorpay_payment_id: z.string(),
      razorpay_order_id: z.string(),
      razorpay_signature: z.string(),
    }))
    .mutation(async ({ input, ctx }): Promise<UserPaymentVerifyResponse> => {
      const { razorpay_payment_id, razorpay_order_id, razorpay_signature } = input;

      // Verify signature
      const encoder = new TextEncoder()
      const key = await crypto.subtle.importKey(
        'raw',
        encoder.encode(getRazorpaySecret()),
        { name: 'HMAC', hash: 'SHA-256' },
        false,
        ['sign']
      )
      const signature = await crypto.subtle.sign(
        'HMAC',
        key,
        encoder.encode(`${razorpay_order_id}|${razorpay_payment_id}`)
      )
      const expectedSignature = Array.from(new Uint8Array(signature))
        .map((byte) => byte.toString(16).padStart(2, '0'))
        .join('')

      if (expectedSignature !== razorpay_signature) {
        throw new ApiError("Invalid payment signature", 400);
      }

      // Get current payment record
      const currentPayment = await getUserPaymentByMerchantOrderIdInDb(razorpay_order_id)

      /*
      // Old implementation - direct DB queries:
      const currentPayment = await db.query.payments.findFirst({
        where: eq(payments.merchantOrderId, razorpay_order_id),
      });
      */

      if (!currentPayment) {
        throw new ApiError("Payment record not found", 404);
      }

      // Update payment status and payload
      const updatedPayload = {
        ...((currentPayment.payload as any) || {}),
        payment_id: razorpay_payment_id,
        signature: razorpay_signature,
      };

      const updatedPayment = await updateUserPaymentSuccessInDb(razorpay_order_id, updatedPayload)

      /*
      // Old implementation - direct DB queries:
      const [updatedPayment] = await db
        .update(payments)
        .set({
          status: 'success',
          payload: updatedPayload,
        })
        .where(eq(payments.merchantOrderId, razorpay_order_id))
        .returning();

      await db
        .update(orderStatus)
        .set({
          paymentStatus: 'success',
        })
        .where(eq(orderStatus.orderId, updatedPayment.orderId));
      */

      if (!updatedPayment) {
        throw new ApiError("Payment record not found", 404)
      }

      await updateUserOrderPaymentStatusInDb(updatedPayment.orderId, 'success')

       return {
        success: true,
        message: "Payment verified successfully",
      }
    }),

  markPaymentFailed: protectedProcedure
    .input(z.object({
      merchantOrderId: z.string(),
    }))
    .mutation(async ({ input, ctx }): Promise<UserPaymentFailResponse> => {
      const userId = ctx.user.userId;
      const { merchantOrderId } = input;

      // Find payment by merchantOrderId
      const payment = await getUserPaymentByMerchantOrderIdInDb(merchantOrderId)

      /*
      // Old implementation - direct DB queries:
      const payment = await db.query.payments.findFirst({
        where: eq(payments.merchantOrderId, merchantOrderId),
      });
      */

      if (!payment) {
        throw new ApiError("Payment not found", 404);
      }

      // Check if payment belongs to user's order
      const order = await getUserPaymentOrderByIdInDb(payment.orderId)

      /*
      // Old implementation - direct DB queries:
      const order = await db.query.orders.findFirst({
        where: eq(orders.id, payment.orderId),
      });
      */

      if (!order || order.userId !== userId) {
        throw new ApiError("Payment does not belong to user", 403);
      }

      // Update payment status to failed
      await markUserPaymentFailedInDb(payment.id)

      /*
      // Old implementation - direct DB queries:
      await db
        .update(payments)
        .set({ status: 'failed' })
        .where(eq(payments.id, payment.id));
      */

      return {
        success: true,
        message: "Payment marked as failed",
      }
    }),

});
