import { Injectable, Logger, BadRequestException, NotFoundException } from '@nestjs/common';
import { Trial, TrialEntity } from '../entities/Trial';
import { User, UserEntity } from '../entities/User';
import { v4 as uuidv4 } from 'uuid';
import knex from 'knex';
import { db } from '../../config/database';

@Injectable()
export class TrialService {
  private readonly logger = new Logger(TrialService.name);
  private knex: knex.Knex;

  constructor() {
    this.knex = db;
  }

  async createTrial(userId: string, plan: 'professional' | 'enterprise'): Promise<Trial> {
    try {
      const user = await this.knex('cf_users').where({ id: userId }).first();

      if (!user) {
        throw new NotFoundException('User not found');
      }

      const existingTrial = await this.knex('cf_trials')
        .where({ userId, status: 'active' })
        .first();

      if (existingTrial) {
        throw new BadRequestException('User already has an active trial');
      }

      const startDate = new Date();
      const endDate = new Date();
      endDate.setDate(endDate.getDate() + 14);

      const trial = TrialEntity.create({
        id: uuidv4(),
        userId,
        planType: plan === 'professional' ? 'PROFESSIONAL' : 'ENTERPRISE',
        startDate,
        endDate,
        status: 'active',
      });

      await this.knex('cf_trials').insert({
        id: trial.id,
        userId: trial.userId,
        planType: trial.planType,
        startDate: trial.startDate,
        endDate: trial.endDate,
        status: trial.status,
        features: JSON.stringify(trial.features),
        usageLimit: JSON.stringify(trial.usageLimit),
        usageUsed: JSON.stringify(trial.usageUsed),
        createdAt: trial.createdAt,
        updatedAt: trial.updatedAt,
      });

      this.logger.log(`Created trial for user ${userId}: ${plan} plan`);
      return trial;
    } catch (error) {
      this.logger.error('Failed to create trial', error);
      throw error;
    }
  }

  async getTrialByUserId(userId: string): Promise<Trial | null> {
    try {
      const row = await this.knex('cf_trials')
        .where({ userId })
        .orderBy('createdAt', 'desc')
        .first();

      if (!row) return null;

      return {
        id: row.id,
        userId: row.userId,
        planType: row.planType,
        startDate: row.startDate,
        endDate: row.endDate,
        status: row.status,
        features: typeof row.features === 'string' ? JSON.parse(row.features) : row.features,
        usageLimit: typeof row.usageLimit === 'string' ? JSON.parse(row.usageLimit) : row.usageLimit,
        usageUsed: typeof row.usageUsed === 'string' ? JSON.parse(row.usageUsed) : row.usageUsed,
        createdAt: row.createdAt,
        updatedAt: row.updatedAt,
      };
    } catch (error) {
      this.logger.error('Failed to get trial', error);
      throw error;
    }
  }

  async endTrial(trialId: string): Promise<boolean> {
    try {
      const trial = await this.knex('cf_trials').where({ id: trialId }).first();

      if (!trial) {
        throw new NotFoundException('Trial not found');
      }

      if (trial.status !== 'active') {
        throw new BadRequestException('Trial is not active');
      }

      await this.knex('cf_trials')
        .where({ id: trialId })
        .update({
          status: 'cancelled',
          updatedAt: new Date(),
        });

      this.logger.log(`Ended trial: ${trialId}`);
      return true;
    } catch (error) {
      this.logger.error('Failed to end trial', error);
      throw error;
    }
  }

  async checkTrialStatus(userId: string): Promise<{
    isActive: boolean;
    trial?: Trial;
    daysRemaining?: number;
  }> {
    try {
      const trial = await this.knex('cf_trials')
        .where({ userId, status: 'active' })
        .first();

      if (!trial) {
        return { isActive: false };
      }

      const now = new Date();
      const endDate = new Date(trial.endDate);
      const daysRemaining = Math.ceil((endDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));

      if (daysRemaining < 0) {
        await this.knex('cf_trials')
          .where({ id: trial.id })
          .update({
            status: 'expired',
            updatedAt: new Date(),
          });
        return { isActive: false };
      }

      return {
        isActive: true,
        trial: {
          id: trial.id,
          userId: trial.userId,
          planType: trial.planType,
          startDate: trial.startDate,
          endDate: trial.endDate,
          status: trial.status,
          features: typeof trial.features === 'string' ? JSON.parse(trial.features) : trial.features,
          usageLimit: typeof trial.usageLimit === 'string' ? JSON.parse(trial.usageLimit) : trial.usageLimit,
          usageUsed: typeof trial.usageUsed === 'string' ? JSON.parse(trial.usageUsed) : trial.usageUsed,
          createdAt: trial.createdAt,
          updatedAt: trial.updatedAt,
        },
        daysRemaining,
      };
    } catch (error) {
      this.logger.error('Failed to check trial status', error);
      throw error;
    }
  }

  async cleanExpiredTrials(): Promise<number> {
    try {
      const now = new Date();
      const expiredTrials = await this.knex('cf_trials')
        .where('status', 'active')
        .where('endDate', '<', now);

      for (const trial of expiredTrials) {
        await this.knex('cf_trials')
          .where({ id: trial.id })
          .update({
            status: 'expired',
            updatedAt: new Date(),
          });
      }

      this.logger.log(`Cleaned ${expiredTrials.length} expired trials`);
      return expiredTrials.length;
    } catch (error) {
      this.logger.error('Failed to clean expired trials', error);
      throw error;
    }
  }
}
