import {
  Controller,
  Get,
  Post,
  Param,
  Body,
  Request,
  Query,
} from '@nestjs/common';
import { DataSource } from 'typeorm';
import { WalletService } from './wallet.service';
import { PaymentsService } from '../payments/payments.service';
import { Public } from '../auth/public.decorator';

@Controller('wallet')
export class WalletController {
  constructor(
    private readonly walletService: WalletService,
    private readonly dataSource: DataSource,
    private readonly paymentsService: PaymentsService,
  ) {}

  @Public()
  @Get('balance')
  async getBalance(@Request() req, @Query('userId') userId?: string) {
    try {
      const id = userId
        ? Number(userId)
        : req.user?.id
          ? Number(req.user.id)
          : 1;
      // console.log('📋 [WALLET BALANCE] Fetching for userId:', id);
      const result = await this.walletService.getBalance(Number(id));
      // console.log('✅ [WALLET BALANCE] Success:', result);
      return result;
    } catch (error) {
      console.error('❌ [WALLET BALANCE] Error:', error);
      throw error;
    }
  }

  @Public()
  @Get('transactions')
  async getTransactions(
    @Request() req,
    @Query('limit') limit: any,
    @Query('offset') offset: any,
    @Query('userId') userId?: string,
    @Query('type') type?: string,
    @Query('creditType') creditType?: string,
    @Query('startDate') startDate?: string,
    @Query('endDate') endDate?: string,
  ) {
    const id = userId ? Number(userId) : req.user?.id ? Number(req.user.id) : 1;
    const limitNum = isNaN(Number(limit)) ? 20 : Number(limit);
    const offsetNum = isNaN(Number(offset)) ? 0 : Number(offset);
    return await this.walletService.getTransactions(
      id,
      limitNum,
      offsetNum,
      type,
      startDate,
      endDate,
      creditType,
    );
  }

  // ✅ ENDPOINT: Get History (Plans or Credit Packs)
  @Public()
  @Get('history')
  async getHistory(
    @Request() req,
    @Query('type') type: 'subscription' | 'credit_pack',
    @Query('status') status: 'active' | 'expired',
    @Query('limit') limit: any,
    @Query('page') page: any,
    @Query('userId') userId?: string,
  ) {
    const id = userId ? Number(userId) : req.user?.id ? Number(req.user.id) : 1;
    const limitNum = isNaN(Number(limit)) ? 10 : Number(limit);
    const pageNum = isNaN(Number(page)) ? 1 : Number(page);
    const offset = (pageNum - 1) * limitNum;

    if (type === 'subscription') {
      return await this.walletService.getSubscriptionHistory(
        id,
        status || 'active',
        limitNum,
        offset,
      );
    } else {
      return await this.walletService.getCreditPackHistory(
        id,
        status || 'active',
        limitNum,
        offset,
      );
    }
  }

  // ✅ ENDPOINT 1: Check if user can afford package
  @Public()
  @Get('check-job-credits/:userId/:packageCode')
  async checkJobCreditsForPackage(
    @Param('userId') userId: string,
    @Param('packageCode') packageCode: string,
  ) {
    // 🔴 EDGE CASE: Validate userId
    const id = Number(userId);
    if (!id || isNaN(id) || id <= 0) {
      return { success: false, error: 'Invalid user ID' };
    }

    // 🔴 LAZY EXPIRY CHECK
    await this.walletService.checkAndProcessExpiry(id);

    // 🔴 EDGE CASE: Check package exists and is active
    const [jobPackage] = await this.dataSource.query(
      'SELECT job_credits, ai_credits, has_ai_interview, name FROM job_packages WHERE code = ? AND is_active = 1',
      [packageCode],
    );

    if (!jobPackage) {
      return { success: false, error: 'Package not found or unavailable' };
    }

    // ✅ Determine credit type (job vs AI)
    const isAiPackage = jobPackage.has_ai_interview || false;
    const creditType = isAiPackage ? 'ai' : 'job';
    const requiredCredits = isAiPackage
      ? jobPackage.ai_credits || 1
      : jobPackage.job_credits || 1;

    // ✅ Get user wallet
    const [wallet] = await this.dataSource.query(
      'SELECT job_credits, ai_credits FROM wallets WHERE user_id = ?',
      [id],
    );

    const availableCredits = isAiPackage
      ? wallet?.ai_credits || 0
      : wallet?.job_credits || 0;

    // 🔴 EDGE CASE: Show helpful message for wrong credit type
    const otherCredits = isAiPackage
      ? wallet?.job_credits || 0
      : wallet?.ai_credits || 0;

    return {
      success: true,
      data: {
        package_name: jobPackage.name,
        credit_type: creditType,
        required_credits: requiredCredits,
        available_credits: availableCredits,
        can_afford: availableCredits >= requiredCredits,
        shortfall: Math.max(0, requiredCredits - availableCredits),
        // Help user understand wrong credit type
        other_credit_type: isAiPackage ? 'job' : 'ai',
        other_credit_balance: otherCredits,
      },
    };
  }

  // ✅ ENDPOINT 2: Deduct credits (with transaction)
  @Public()
  @Post('deduct-job-credits')
  async deductJobCredits(
    @Body() body: { userId: number; packageCode: string },
  ) {
    try {
      return await this.walletService.deductJobCreditsForPackage(
        body.userId,
        body.packageCode,
      );
    } catch (error) {
      return {
        success: false,
        message: error.message || 'Failed to deduct credits',
      };
    }
  }

  // ✅ ENDPOINT 3: Manual Admin Adjustment
  // @UseGuards(RolesGuard) // Enable this when roles are fully setup
  // @Roles('admin')
  @Public() // For now public, secure later
  @Post('manual-adjustment')
  async manualAdjustment(
    @Body()
    body: {
      userId: number;
      operation: 'credit' | 'debit';
      sourceType?: string; // Optional source type (adjustment, refund, etc.)
      adjustments: Array<{
        creditType: 'job' | 'database' | 'ai';
        amount: number;
        validityDays?: number;
      }>;
      remarks: string;
      generateInvoice?: boolean;
      invoiceAmount?: number;
    },
  ) {
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      const {
        userId,
        operation,
        sourceType,
        adjustments,
        remarks,
        generateInvoice,
        invoiceAmount,
      } = body;

      if (!userId || !adjustments || !adjustments.length || !operation) {
        return { success: false, message: 'Missing required fields' };
      }

      const refType = sourceType || 'admin_adjustment';
      const adminRemark = `Admin Manual: ${remarks || 'Adjustment'}`;
      let invoiceDescription = `Manual ${operation === 'credit' ? 'Credit' : 'Debit'}: `;
      const descParts = [];

      for (const adj of adjustments) {
        const { creditType, amount, validityDays } = adj;

        if (!amount || amount <= 0) continue;

        if (operation === 'credit') {
          const expiresAt =
            validityDays && Number(validityDays) > 0
              ? new Date(
                  Date.now() + Number(validityDays) * 24 * 60 * 60 * 1000,
                )
              : undefined;

          await this.walletService.creditWallet(
            userId,
            creditType,
            amount,
            adminRemark,
            refType,
            0,
            queryRunner.manager,
            expiresAt,
          );
          descParts.push(
            `${amount} ${creditType.toUpperCase()} (${validityDays || 'No'} days)`,
          );
        } else {
          await this.walletService.debitWallet(
            userId,
            creditType,
            amount,
            adminRemark,
            refType,
            0,
            queryRunner.manager,
          );
          descParts.push(`${amount} ${creditType.toUpperCase()}`);
        }
      }

      invoiceDescription += descParts.join(', ');

      // ✅ Generate Invoice if Requested (Only for Credit)
      if (
        operation === 'credit' &&
        generateInvoice &&
        invoiceAmount &&
        Number(invoiceAmount) > 0
      ) {
        await this.paymentsService.createOfflineInvoice(
          userId,
          Number(invoiceAmount),
          invoiceDescription,
          18,
          queryRunner.manager, // Pass manager if createOfflineInvoice supports it
        );
      }

      await queryRunner.commitTransaction();

      const newBalance = await this.walletService.getBalance(userId);

      return {
        success: true,
        message: `Successfully processed ${operation} adjustments`,
        newBalance,
      };
    } catch (error) {
      await queryRunner.rollbackTransaction();
      return {
        success: false,
        message: error.message || 'Failed to process adjustment',
      };
    } finally {
      await queryRunner.release();
    }
  }
}
