import { z } from "zod";
import { protectedProcedure, publicProcedure, router } from "../_core/trpc.ts";
import { TRPCError } from "@trpc/server";
import { getDb, creditWallet, writeAuditLog, getUserById, updateUser, getCoinPackages } from "../db.ts";
import { notifyOwner } from "../_core/notification.ts";
import { SquareClient } from "square";
import { v4 as uuidv4 } from "uuid";
import nodemailer from "nodemailer";

// Initialize Square client
const squareClient = new SquareClient({
  accessToken: process.env.SQUARE_ACCESS_TOKEN,
  environment: "production",
});

// Initialize email transporter
const emailTransporter = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: process.env.ADMIN_EMAIL || "coinkrazy26@gmail.com",
    pass: process.env.ADMIN_EMAIL_PASSWORD || "",
  },
});

async function sendAdminNotification(transaction: any, user: any) {
  try {
    const emailContent = `
      <h2>New Transaction Received</h2>
      <p><strong>User:</strong> ${user.name || user.email}</p>
      <p><strong>User ID:</strong> ${user.id}</p>
      <p><strong>Package:</strong> ${transaction.packageName}</p>
      <p><strong>Amount:</strong> $${transaction.amount}</p>
      <p><strong>Gold Coins:</strong> ${transaction.gcAmount}</p>
      <p><strong>Bonus SC:</strong> ${transaction.scBonus}</p>
      <p><strong>Transaction ID:</strong> ${transaction.squareTransactionId}</p>
      <p><strong>Date:</strong> ${new Date(transaction.createdAt).toLocaleString()}</p>
      <p><strong>Status:</strong> ${transaction.status}</p>
    `;

    await emailTransporter.sendMail({
      from: process.env.ADMIN_EMAIL || "coinkrazy26@gmail.com",
      to: process.env.ADMIN_EMAIL || "coinkrazy26@gmail.com",
      subject: `New Purchase: ${transaction.packageName} - $${transaction.amount}`,
      html: emailContent,
    });
  } catch (err) {
    console.error("[Email] Failed to send admin notification:", err);
  }
}

async function sendUserConfirmationEmail(user: any, transaction: any) {
  try {
    const emailContent = `
      <h2>Thank You for Your Purchase!</h2>
      <p>Hi ${user.name || "Player"},</p>
      <p>Your purchase has been successfully completed. Here are your details:</p>
      <ul>
        <li><strong>Package:</strong> ${transaction.packageName}</li>
        <li><strong>Gold Coins:</strong> ${transaction.gcAmount}</li>
        <li><strong>Bonus Sweep Coins:</strong> ${transaction.scBonus}</li>
        <li><strong>Amount Paid:</strong> $${transaction.amount}</li>
        <li><strong>Transaction ID:</strong> ${transaction.squareTransactionId}</li>
      </ul>
      <p>Your coins have been credited to your account. You can now continue playing!</p>
      <p>Best regards,<br>CoinKrazy Team</p>
    `;

    await emailTransporter.sendMail({
      from: process.env.ADMIN_EMAIL || "coinkrazy26@gmail.com",
      to: user.email,
      subject: "Purchase Confirmation - CoinKrazy",
      html: emailContent,
    });
  } catch (err) {
    console.error("[Email] Failed to send user confirmation:", err);
  }
}

export const paymentRouter = router({
  // Create a Square payment link for coin purchase
  createPaymentLink: protectedProcedure
    .input(z.object({ packageId: z.number().min(1) }))
    .mutation(async ({ ctx, input }) => {
      if (!process.env.SQUARE_ACCESS_TOKEN) {
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Square is not configured",
        });
      }

      // Fetch package from database
      const packages = await getCoinPackages();
      const pkg = packages.find(p => p.id === input.packageId);
      if (!pkg) throw new TRPCError({ code: "NOT_FOUND", message: "Package not found" });
      if (!pkg.isActive) throw new TRPCError({ code: "BAD_REQUEST", message: "Package is not available" });

      const gcAmount = parseFloat(pkg.gcAmount);
      const scBonus = parseFloat(pkg.scBonusAmount);
      const priceUsd = parseFloat(pkg.priceUsd);

      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      try {
        const origin = ctx.req.headers.origin || "https://playplaycoinkrazy.com";
        const idempotencyKey = uuidv4();
        
        // Create Square payment link
        const paymentLinkResponse = await (squareClient as any).checkoutApi.createPaymentLink({
          idempotencyKey,
          paymentLink: {
            description: `${gcAmount.toLocaleString()} Gold Coins${scBonus > 0 ? ` + ${scBonus} Bonus SC` : ""}`,
            checkoutOptions: {
              askForShippingAddress: false,
              redirectUrl: `${origin}/wallet?payment=success&packageId=${input.packageId}`,
            },
            prePopulatedData: {
              buyerEmail: ctx.user.email || undefined,
            },
            lineItems: [
              {
                uid: `line_${pkg.id}`,
                title: pkg.name,
                description: `${gcAmount.toLocaleString()} Gold Coins${scBonus > 0 ? ` + ${scBonus} Bonus SC` : ""}`,
                quantity: "1",
                priceMoneyObject: {
                  amount: BigInt(Math.round(priceUsd * 100)),
                  currency: "USD",
                },
                customData: JSON.stringify({
                  userId: ctx.user.id,
                  packageId: pkg.id,
                  gcAmount,
                  scBonus,
                  userName: ctx.user.name,
                  userEmail: ctx.user.email,
                }),
              },
            ],
          },
        });

        if (!paymentLinkResponse.result?.paymentLink?.url) {
          console.error("[Payment] No payment link URL returned:", paymentLinkResponse);
          throw new TRPCError({
            code: "INTERNAL_SERVER_ERROR",
            message: "Failed to create payment link - no URL returned from Square",
          });
        }

        // Log the payment link creation
        await writeAuditLog(db, {
          userId: ctx.user.id,
          action: "payment_link_created",
          details: `Created payment link for package ${pkg.id}`,
          metadata: {
            packageId: pkg.id,
            amount: priceUsd,
            paymentLinkId: paymentLinkResponse.result.paymentLink.id,
          },
        });

        const paymentUrl = paymentLinkResponse.result.paymentLink.url;
        const paymentLinkId = paymentLinkResponse.result.paymentLink.id;
        
        console.log("[Payment] Payment link created successfully:", { paymentLinkId, paymentUrl });
        
        return {
          paymentUrl,
          paymentLinkId,
        };
      } catch (err: any) {
        console.error("[Payment] Error creating payment link:", err);
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: err.message || "Failed to create payment link",
        });
      }
    }),

  // Process payment and credit user account
  processPayment: protectedProcedure
    .input(
      z.object({
        paymentLinkId: z.string(),
        packageId: z.number(),
        squareTransactionId: z.string(),
        amount: z.number(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      try {
        // Fetch package details
        const packages = await getCoinPackages();
        const pkg = packages.find(p => p.id === input.packageId);
        if (!pkg) throw new TRPCError({ code: "NOT_FOUND", message: "Package not found" });

        const gcAmount = parseFloat(pkg.gcAmount);
        const scBonus = parseFloat(pkg.scBonusAmount);

        // Credit user's wallet
        const creditResult = await creditWallet(db, {
          userId: ctx.user.id,
          gcAmount,
          scAmount: scBonus,
          reason: `Purchase: ${pkg.name}`,
          transactionId: input.squareTransactionId,
        });

        if (!creditResult.success) {
          throw new TRPCError({
            code: "INTERNAL_SERVER_ERROR",
            message: "Failed to credit wallet",
          });
        }

        // Create transaction record
        const transaction = {
          userId: ctx.user.id,
          packageId: input.packageId,
          packageName: pkg.name,
          amount: input.amount,
          gcAmount,
          scBonus,
          squareTransactionId: input.squareTransactionId,
          paymentLinkId: input.paymentLinkId,
          status: "completed",
          createdAt: new Date().toISOString(),
        };

        // Log transaction
        await writeAuditLog(db, {
          userId: ctx.user.id,
          action: "payment_completed",
          details: `Purchased ${pkg.name} for $${input.amount}`,
          metadata: {
            packageId: input.packageId,
            amount: input.amount,
            gcAmount,
            scBonus,
            squareTransactionId: input.squareTransactionId,
          },
        });

        // Get user details for email
        const user = await getUserById(db, ctx.user.id);
        if (!user) throw new TRPCError({ code: "NOT_FOUND", message: "User not found" });

        // Send notifications
        await sendAdminNotification(transaction, user);
        await sendUserConfirmationEmail(user, transaction);

        // Notify owner
        await notifyOwner({
          title: `New Purchase: ${pkg.name}`,
          content: `${user.name || user.email} purchased ${pkg.name} for $${input.amount}. Transaction ID: ${input.squareTransactionId}`,
        });

        return {
          success: true,
          transaction,
          message: "Payment processed successfully",
        };
      } catch (err: any) {
        console.error("[Payment] Error processing payment:", err);
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: err.message || "Failed to process payment",
        });
      }
    }),

  // Get transaction history
  getTransactionHistory: protectedProcedure
    .input(z.object({ limit: z.number().optional() }).optional())
    .query(async ({ ctx }) => {
      const db = await getDb();
      if (!db) throw new Error("Database unavailable");

      try {
        // This would query the transactions table if it exists
        // For now, return empty array
        return [];
      } catch (err: any) {
        console.error("[Payment] Error fetching transaction history:", err);
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: "Failed to fetch transaction history",
        });
      }
    }),
});

// Webhook handler (exported for server setup)
export async function handleSquarePaymentWebhook(event: any) {
  const db = await getDb();
  if (!db) {
    console.error("[Square Webhook] Database unavailable");
    return;
  }

  try {
    console.log("[Square Webhook] Processing event:", event.type);

    // Handle payment completion
    if (event.type === "payment.created" || event.type === "payment.updated") {
      const payment = event.data?.object?.payment;
      if (!payment || payment.status !== "COMPLETED") {
        console.log("[Square Webhook] Payment not completed, skipping");
        return;
      }

      console.log("[Square Webhook] Payment completed:", payment.id);
      // Payment processing is handled by the processPayment mutation
    }
  } catch (err: any) {
    console.error("[Square Webhook] Error processing event:", err.message);
  }
}
