import { Injectable } from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import { CreateRewardDto } from "./dto/create-reward.dto";
import { UpdateRewardDto } from "./dto/update-reward.dto";
import { Model, Types } from "mongoose";
import {
  UserSubscription,
  UserSubscriptionDocument,
} from "src/schema/user-subscription.schema";
import {
  SubscriptionPlan,
  SubscriptionPlanDocument,
} from "src/schema/subscription.schema";
import { Wallet, WalletDocument } from "src/schema/wallet.schema";
import {
  RewardTransaction,
  RewardTransactionDocument,
} from "src/schema/reward-transaction.schema";
import { Invoice, InvoiceDocument } from "src/schema/invoice.schema";
import { Users, UsersDocument } from "src/schema/users.schema";
import { ResponseService } from "src/common/service/response.service";
import { Response } from "express";

@Injectable()
export class RewardService {
  constructor(
    @InjectModel(UserSubscription.name)
    private readonly userSubscriptionModel: Model<UserSubscriptionDocument>,
    @InjectModel(SubscriptionPlan.name)
    private readonly subscriptionPlanModel: Model<SubscriptionPlanDocument>,
    @InjectModel(Wallet.name)
    private readonly walletModel: Model<WalletDocument>,
    @InjectModel(RewardTransaction.name)
    private readonly rewardTransactionModel: Model<RewardTransactionDocument>,
    @InjectModel(Invoice.name)
    private readonly invoiceModel: Model<InvoiceDocument>,
    @InjectModel(Users.name)
    private readonly usersModel: Model<UsersDocument>,
    private readonly resService: ResponseService,
  ) {}

  async handleReward(userId: string, invoice: any) {
    try {
      console.log(userId, "userId");
      const userObjectId = new Types.ObjectId(userId);
      console.log(userObjectId, "userobjected");
      const subscription = await this.userSubscriptionModel
        .findOne({ userId: userObjectId })
        .populate("planId");
      if (!subscription) return;
console.log(subscription , "subscription")
      const now = Date.now();
      const expiry = new Date(subscription.expiryDate).getTime();
      if (expiry <= now) return;
      const plan: any = subscription.planId;
      if (invoice.total < plan.minInvoiceAmount) return;
      if (subscription.rewardedInvoicesCount >= plan.invoiceRewardLimit) {
        return;
      }
      if (invoice.isRewardGenerated) return;
      const cashback = (invoice.total * plan.cashbackPercent) / 100;

      await this.walletModel.updateOne(
        { userId: userObjectId },
        {
          $inc: {
            balance: cashback,
            totalEarned: cashback,
          },
        },
        { upsert: true },
      );
      console.log("saved in wallet");

      await this.rewardTransactionModel.create({
        userId: userObjectId,
        invoiceId: invoice._id,
        rewardAmount: cashback,
        type: "cashback",
      });

      console.log("saved in reward");

      await this.userSubscriptionModel.updateOne(
        { _id: subscription._id },
        { $inc: { rewardedInvoicesCount: 1 } },
      );
      await this.invoiceModel.updateOne(
        { _id: invoice._id },
        { isRewardGenerated: true },
      );

      console.log("invoice modal updated ");
    } catch (err) {
      console.error("Reward Error:", err);
    }
  }

  async handleRewardUpdate(userId: string, invoice: any) {
    try {
      const userObjectId = new Types.ObjectId(userId);
      const subscription = await this.userSubscriptionModel
        .findOne({ userId: userObjectId })
        .populate("planId");

      if (!subscription) return;

      if (subscription.expiryDate < new Date()) return;

      const plan: any = subscription.planId;
      if (!plan) return;

      const isEligible =
        invoice.total >= plan.minInvoiceAmount &&
        subscription.rewardedInvoicesCount < plan.invoiceRewardLimit;

      console.log(isEligible, "isEligible");

      //  Find existing reward transaction
      const existingReward = await this.rewardTransactionModel.findOne({
        invoiceId: invoice._id,
        userId: userObjectId,
        type: "cashback",
      });

      console.log(existingReward, "existing reward ");
      //  CASE 1: Deduct reward

      if (!isEligible && existingReward) {
        const amount = existingReward.rewardAmount;

        // Deduct from wallet
        await this.walletModel.updateOne(
          { userId: userObjectId },
          {
            $inc: {
              balance: -amount,
              totalEarned: -amount,
            },
          },
        );

        // Delete reward transaction
        await this.rewardTransactionModel.deleteOne({
          _id: existingReward._id,
        });

        // Decrease subscription count
        await this.userSubscriptionModel.updateOne(
          { _id: subscription._id },
          { $inc: { rewardedInvoicesCount: -1 } },
        );

        // Mark invoice
        await this.invoiceModel.updateOne(
          { _id: invoice._id },
          { isRewardGenerated: false },
        );

        return;
      }

      // Add reward

      if (isEligible && !existingReward) {
        console.log("reward is getting added ");
        const cashback = (invoice.total * plan.cashbackPercent) / 100;

        // Prevent duplicate
        const updatedInvoice = await this.invoiceModel.findOneAndUpdate(
          { _id: invoice._id, isRewardGenerated: { $ne: true } },
          { isRewardGenerated: true },
          { new: true },
        );

        if (!updatedInvoice) return;
        await this.walletModel.updateOne(
          { userId: userObjectId },
          {
            $inc: {
              balance: cashback,
              totalEarned: cashback,
            },
          },
          { upsert: true },
        );

        await this.rewardTransactionModel.create({
          userId: userObjectId,
          invoiceId: invoice._id,
          rewardAmount: cashback,
          type: "cashback",
        });

        await this.userSubscriptionModel.updateOne(
          { _id: subscription._id },
          { $inc: { rewardedInvoicesCount: 1 } },
        );

        return;
      }
    } catch (err) {
      console.error("Reward Update Error:", err);
    }
  }

  

  async rewardHistory(userId: string, res: Response) {
    try {
      const userObjectId = new Types.ObjectId(userId);

      //  user join date
      const user: any = await this.usersModel
        .findById(userObjectId)
        .select("createdAt");

      if (!user) {
        return this.resService.notFound(res, "User not found");
      }

      const startDate = new Date(user.createdAt);
      const currentDate = new Date();

      //  reward data
      const rewardData = await this.rewardTransactionModel.aggregate([
        {
          $match: {
            userId: userObjectId,
            type: "cashback",
          },
        },
        {
          $addFields: {
            year: { $year: "$createdAt" },
            month: { $month: "$createdAt" },
          },
        },
        {
          $group: {
            _id: { year: "$year", month: "$month" },
            totalAmount: { $sum: "$rewardAmount" },
            invoiceCount: { $sum: 1 },
          },
        },
      ]);

      // Convert to map for quick lookup
      const rewardMap = new Map();
      rewardData.forEach((item) => {
        const key = `${item._id.year}-${item._id.month}`;
        rewardMap.set(key, {
          amount: item.totalAmount,
          invoiceCount: item.invoiceCount,
        });
      });

      // 3. Generate all months
      const history: Array<{
        month: string;
        amount: number;
        invoiceCount: number;
      }> = [];

      let tempDate = new Date(startDate.getFullYear(), startDate.getMonth(), 1);

      while (tempDate <= currentDate) {
        const year = tempDate.getFullYear();
        const month = tempDate.getMonth() + 1;

        const key = `${year}-${month}`;
        const data = rewardMap.get(key) || { amount: 0, invoiceCount: 0 };

        const monthName = tempDate.toLocaleString("en-US", {
          month: "long",
          year: "numeric",
        });

        history.push({
          month: monthName,
          amount: data.amount,
          invoiceCount: data.invoiceCount,
        });

        // Move to next month
        tempDate.setMonth(tempDate.getMonth() + 1);
      }

      // Sort latest first
      history.reverse();
      const totalEarned = history.reduce((sum, item) => sum + item.amount, 0);

      const totalMonths = history.length;

      return this.resService.success(res, {
        totalEarned,
        totalMonths,
        history,
      });
    } catch (err) {
      console.error("Reward History Error:", err);
      return res.status(500).json({
        success: false,
        message: "Something went wrong",
      });
    }
  }
}
