import { Injectable, Logger, BadRequestException, NotFoundException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaService } from '../../database/prisma.service';
import Stripe from 'stripe';

/**
 * Billing Service — Stripe entegrasyonu
 * 
 * stripe-integration + pricing-strategy skill'lerinden elde
 * edilen bilgilerle tasarlandı.
 * 
 * Akış:
 * 1. Kullanıcı plan seçer → Stripe Checkout Session oluşturulur
 * 2. Ödeme → Stripe Webhook → subscription aktif → kredi yüklenir
 * 3. Her video üretiminde kredi harcanır
 * 4. Ay sonu → kredi sıfırlanır (rollover yok)
 */

@Injectable()
export class BillingService {
  private readonly logger = new Logger(BillingService.name);
  private readonly stripe: Stripe | null;

  constructor(
    private readonly db: PrismaService,
    private readonly configService: ConfigService,
  ) {
    const stripeKey = this.configService.get<string>('STRIPE_SECRET_KEY');

    if (stripeKey) {
      this.stripe = new Stripe(stripeKey);
      this.logger.log('💳 Stripe bağlantısı kuruldu');
    } else {
      this.stripe = null;
      this.logger.warn('⚠️ STRIPE_SECRET_KEY ayarlanmamış — Ödeme sistemi devre dışı');
    }
  }

  /**
   * Checkout Session oluştur — Value-Based Pricing (pricing-strategy skill)
   */
  async createCheckoutSession(userId: string, planName: string, billingCycle: 'monthly' | 'yearly') {
    if (!this.stripe) {
      throw new BadRequestException('Ödeme sistemi şu anda aktif değil');
    }

    const plan = await this.db.plan.findFirst({
      where: { name: planName, isActive: true },
    });

    if (!plan) {
      throw new NotFoundException(`Plan bulunamadı: ${planName}`);
    }

    const user = await this.db.user.findUnique({
      where: { id: userId },
      select: { email: true },
    });

    if (!user) {
      throw new NotFoundException('Kullanıcı bulunamadı');
    }

    const priceId = billingCycle === 'yearly'
      ? plan.stripeYearlyPriceId
      : plan.stripePriceId;

    if (!priceId) {
      throw new BadRequestException(`Bu plan için ${billingCycle} fiyat tanımlı değil`);
    }

    const session = await this.stripe.checkout.sessions.create({
      mode: 'subscription',
      payment_method_types: ['card'],
      customer_email: user.email,
      line_items: [
        {
          price: priceId,
          quantity: 1,
        },
      ],
      metadata: {
        userId,
        planId: plan.id,
        planName: plan.name,
      },
      success_url: `${this.configService.get('APP_URL')}/dashboard?checkout=success&plan=${planName}`,
      cancel_url: `${this.configService.get('APP_URL')}/dashboard/pricing?checkout=cancelled`,
    });

    this.logger.log(`Checkout session oluşturuldu: ${session.id} — Plan: ${planName}`);

    return {
      sessionId: session.id,
      url: session.url,
    };
  }

  /**
   * Webhook handler — Stripe event işleme
   * State machine: checkout.session.completed → subscription aktif → kredi yükle
   */
  async handleWebhookEvent(event: Stripe.Event): Promise<void> {
    switch (event.type) {
      case 'checkout.session.completed':
        await this.handleCheckoutComplete(event.data.object as Stripe.Checkout.Session);
        break;

      case 'invoice.payment_succeeded':
        await this.handlePaymentSucceeded(event.data.object as Stripe.Invoice);
        break;

      case 'customer.subscription.updated':
        await this.handleSubscriptionUpdated(event.data.object as Stripe.Subscription);
        break;

      case 'customer.subscription.deleted':
        await this.handleSubscriptionDeleted(event.data.object as Stripe.Subscription);
        break;

      default:
        this.logger.debug(`Unhandled webhook event: ${event.type}`);
    }
  }

  /**
   * Aktif planları listele — pricing sayfası için
   */
  async getPlans() {
    const plans = await this.db.plan.findMany({
      where: { isActive: true },
      orderBy: { sortOrder: 'asc' },
      select: {
        id: true,
        name: true,
        displayName: true,
        description: true,
        monthlyPrice: true,
        yearlyPrice: true,
        currency: true,
        monthlyCredits: true,
        maxDuration: true,
        maxResolution: true,
        maxProjects: true,
        features: true,
      },
    });

    return plans;
  }

  /**
   * Kullanıcının admin rolü olup olmadığını kontrol et
   */
  private async isAdmin(userId: string): Promise<boolean> {
    const userRoles = await this.db.userRole.findMany({
      where: { userId },
      include: { role: true },
    });
    return userRoles.some((ur) => ur.role.name === 'admin' || ur.role.name === 'superadmin');
  }

  /**
   * Kullanıcı kredi bakiyesi
   */
  async getCreditBalance(userId: string) {
    // Admin kullanıcılar için sınırsız kredi
    const admin = await this.isAdmin(userId);
    if (admin) {
      return {
        balance: 999999,
        monthlyUsed: 0,
        monthlyLimit: 999999,
        plan: 'Admin',
        remaining: 999999,
        total: 999999,
        isAdmin: true,
      };
    }

    const transactions = await this.db.creditTransaction.findMany({
      where: { userId },
      orderBy: { createdAt: 'desc' },
    });

    const balance = transactions.reduce((sum, tx) => sum + tx.amount, 0);

    // Bu ayın kullanımı
    const monthStart = new Date();
    monthStart.setDate(1);
    monthStart.setHours(0, 0, 0, 0);

    const monthlyTransactions = transactions.filter(
      (tx) => tx.amount < 0 && new Date(tx.createdAt) >= monthStart,
    );
    const monthlyUsed = Math.abs(monthlyTransactions.reduce((sum, tx) => sum + tx.amount, 0));

    // Kullanıcının aktif planından limit al
    const subscription = await this.db.subscription.findFirst({
      where: { userId, status: 'active' },
      include: { plan: true },
    });

    const monthlyLimit = subscription?.plan?.monthlyCredits || 3;

    return {
      balance,
      monthlyUsed,
      monthlyLimit,
      plan: subscription?.plan?.displayName || 'Free',
      remaining: balance,
      total: monthlyLimit,
      isAdmin: false,
    };
  }

  /**
   * Kredi harca (video üretimi için)
   */
  async spendCredits(userId: string, amount: number, projectId: string, description: string) {
    // Admin bypass — sınırsız kredi
    const admin = await this.isAdmin(userId);
    if (admin) {
      this.logger.log(`🛡️ Admin kredi bypass: ${amount} — User: ${userId}, Project: ${projectId}`);
      return { id: 'admin-bypass', amount: -amount, type: 'usage', description };
    }

    const balance = await this.getCreditBalance(userId);

    if (balance.balance < amount) {
      throw new BadRequestException(
        `Yetersiz kredi. Mevcut: ${balance.balance}, Gerekli: ${amount}`,
      );
    }

    const transaction = await this.db.creditTransaction.create({
      data: {
        userId,
        amount: -amount,
        type: 'usage',
        description,
        projectId,
        balanceAfter: balance.balance - amount,
      },
    });

    this.logger.log(`Kredi harcandı: -${amount} — User: ${userId}, Project: ${projectId}`);
    return transaction;
  }

  /**
   * Kredi ekle (abonelik yenileme, bonus vb.)
   */
  async grantCredits(userId: string, amount: number, type: string, description: string) {
    const currentBalance = await this.getCreditBalance(userId);

    const transaction = await this.db.creditTransaction.create({
      data: {
        userId,
        amount,
        type,
        description,
        balanceAfter: currentBalance.balance + amount,
      },
    });

    this.logger.log(`Kredi eklendi: +${amount} — User: ${userId}, Type: ${type}`);
    return transaction;
  }

  // ── Private: Webhook handlers ──────────────────────────────────────

  private async handleCheckoutComplete(session: Stripe.Checkout.Session) {
    const userId = session.metadata?.userId;
    const planId = session.metadata?.planId;

    if (!userId || !planId) {
      this.logger.error('Checkout metadata eksik');
      return;
    }

    const plan = await this.db.plan.findUnique({ where: { id: planId } });
    if (!plan) return;

    // Subscription kaydı oluştur
    await this.db.subscription.create({
      data: {
        userId,
        planId,
        status: 'active',
        stripeSubscriptionId: session.subscription as string,
        stripeCustomerId: session.customer as string,
        currentPeriodStart: new Date(),
        currentPeriodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
      },
    });

    // İlk ay kredilerini yükle
    await this.grantCredits(userId, plan.monthlyCredits, 'grant', `${plan.displayName} abonelik kredisi`);

    this.logger.log(`✅ Abonelik aktif: User ${userId}, Plan ${plan.name}`);
  }

  private async handlePaymentSucceeded(invoice: Stripe.Invoice) {
    const inv = invoice as any;
    const subscriptionId = typeof inv.subscription === 'string'
      ? inv.subscription
      : inv.subscription?.id;
    if (!subscriptionId) return;

    const subscription = await this.db.subscription.findFirst({
      where: { stripeSubscriptionId: subscriptionId },
      include: { plan: true },
    });

    if (!subscription) return;

    // Aylık kredi yenileme
    await this.grantCredits(
      subscription.userId,
      subscription.plan.monthlyCredits,
      'grant',
      `${subscription.plan.displayName} aylık kredi yenileme`,
    );

    this.logger.log(`💰 Ödeme başarılı — kredi yenilendi: ${subscription.userId}`);
  }

  private async handleSubscriptionUpdated(stripeSubscription: Stripe.Subscription) {
    const periodStart = (stripeSubscription as any).current_period_start;
    const periodEnd = (stripeSubscription as any).current_period_end;

    await this.db.subscription.updateMany({
      where: { stripeSubscriptionId: stripeSubscription.id },
      data: {
        status: stripeSubscription.status,
        cancelAtPeriodEnd: stripeSubscription.cancel_at_period_end,
        ...(periodStart && { currentPeriodStart: new Date(periodStart * 1000) }),
        ...(periodEnd && { currentPeriodEnd: new Date(periodEnd * 1000) }),
      },
    });
  }

  private async handleSubscriptionDeleted(stripeSubscription: Stripe.Subscription) {
    await this.db.subscription.updateMany({
      where: { stripeSubscriptionId: stripeSubscription.id },
      data: {
        status: 'canceled',
        canceledAt: new Date(),
      },
    });

    this.logger.log(`❌ Abonelik iptal edildi: ${stripeSubscription.id}`);
  }

  /**
   * Kredi işlem geçmişi (son 50)
   */
  async getCreditHistory(userId: string) {
    const transactions = await this.db.creditTransaction.findMany({
      where: { userId },
      orderBy: { createdAt: 'desc' },
      take: 50,
      select: {
        id: true,
        amount: true,
        type: true,
        description: true,
        balanceAfter: true,
        createdAt: true,
      },
    });

    return { transactions };
  }

  /**
   * Aktif abonelik bilgisi
   */
  async getActiveSubscription(userId: string) {
    const subscription = await this.db.subscription.findFirst({
      where: { userId, status: 'active' },
      include: { plan: true },
    });

    if (!subscription) {
      return {
        plan: 'Free',
        status: 'free',
        monthlyCredits: 3,
        currentPeriodEnd: null,
      };
    }

    return {
      plan: subscription.plan.displayName,
      status: subscription.status,
      monthlyCredits: subscription.plan.monthlyCredits,
      currentPeriodEnd: subscription.currentPeriodEnd,
      cancelAtPeriodEnd: subscription.cancelAtPeriodEnd,
      stripeSubscriptionId: subscription.stripeSubscriptionId,
    };
  }
}
