import { Injectable, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Like } from 'typeorm';
import { User } from '../../entities/user.entity';
import { License } from '../../entities/license.entity';
import { ServerConnection } from '../../entities/server-connection.entity';
import { WebstoreSubscription } from '../../entities/webstore-subscription.entity';
import * as crypto from 'crypto';
import * as argon2 from 'argon2';

@Injectable()
export class AdminService {
  constructor(
    @InjectRepository(User)
    private readonly userRepo: Repository<User>,
    @InjectRepository(License)
    private readonly licenseRepo: Repository<License>,
    @InjectRepository(ServerConnection)
    private readonly serverConnectionRepo: Repository<ServerConnection>,
    @InjectRepository(WebstoreSubscription)
    private readonly webstoreSubRepo: Repository<WebstoreSubscription>,
  ) {}

  async getStats() {
    const [totalUsers, totalLicenses, activeServers] = await Promise.all([
      this.userRepo.count(),
      this.licenseRepo.count(),
      this.serverConnectionRepo.count({
        where: { connection_status: 'connected' },
      }),
    ]);

    return {
      total_users: totalUsers,
      total_licenses: totalLicenses,
      active_servers: activeServers,
    };
  }

  async getLicenses(page: number = 1, limit: number = 25, search?: string) {
    const skip = (page - 1) * limit;

    const queryBuilder = this.licenseRepo
      .createQueryBuilder('license')
      .leftJoinAndSelect('license.owner', 'owner')
      .orderBy('license.created_at', 'DESC')
      .skip(skip)
      .take(limit);

    if (search) {
      queryBuilder.where(
        '(license.license_key ILIKE :search OR license.server_name ILIKE :search OR license.subdomain ILIKE :search OR owner.email ILIKE :search)',
        { search: `%${search}%` },
      );
    }

    const [licenses, total] = await queryBuilder.getManyAndCount();

    return {
      data: licenses.map(l => ({
        id: l.id,
        license_key: l.license_key,
        owner_email: l.owner?.email ?? '',
        server_name: l.server_name,
        status: l.status,
        created_at: l.created_at,
        expires_at: l.expires_at,
      })),
      total,
    };
  }

  async getLicenseById(id: string) {
    return this.licenseRepo.findOne({
      where: { id },
      relations: ['owner'],
    });
  }

  async createLicense(email: string) {
    // Find or create user
    let user = await this.userRepo.findOne({ where: { email } });

    if (!user) {
      // Create new user with random password
      const randomPassword = crypto.randomBytes(16).toString('hex');
      const passwordHash = await argon2.hash(randomPassword);
      const username = email.split('@')[0] + '_' + Math.random().toString(36).substr(2, 5);

      user = this.userRepo.create({
        email,
        username,
        password_hash: passwordHash,
      });
      await this.userRepo.save(user);
    }

    // Create license (branded CORR-XXXX-XXXX-XXXX format)
    const part1 = crypto.randomBytes(2).toString('hex').toUpperCase();
    const part2 = crypto.randomBytes(2).toString('hex').toUpperCase();
    const part3 = crypto.randomBytes(2).toString('hex').toUpperCase();
    const licenseKey = `CORR-${part1}-${part2}-${part3}`;
    const license = this.licenseRepo.create({
      license_key: licenseKey,
      owner_user_id: user.id,
      status: 'active',
    });

    return this.licenseRepo.save(license);
  }

  async getUsers(page: number = 1, limit: number = 25) {
    const skip = (page - 1) * limit;

    const [users, total] = await this.userRepo.findAndCount({
      order: { created_at: 'DESC' },
      skip,
      take: limit,
    });

    return {
      data: users.map(u => ({
        id: u.id,
        email: u.email,
        username: u.username,
        is_super_admin: u.is_super_admin,
        email_verified: u.email_verified,
        totp_enabled: u.totp_enabled,
        created_at: u.created_at,
        last_login_at: u.last_login_at,
      })),
      pagination: {
        page,
        limit,
        total,
        total_pages: Math.ceil(total / limit),
      },
    };
  }

  async updateUser(userId: string, data: Partial<User>) {
    const user = await this.userRepo.findOne({ where: { id: userId } });

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

    // Only allow updating specific fields
    if (typeof data.is_super_admin !== 'undefined') {
      user.is_super_admin = data.is_super_admin;
    }
    if (typeof data.email_verified !== 'undefined') {
      user.email_verified = data.email_verified;
    }

    return this.userRepo.save(user);
  }

  async getSubscriptions() {
    const subs = await this.webstoreSubRepo.find({
      relations: ['license', 'license.owner'],
      order: { created_at: 'DESC' },
    });

    return {
      subscriptions: subs.map(sub => ({
        owner_email: sub.license?.owner?.email ?? 'Unknown',
        module_name: sub.plan_id,
        license_id: sub.license_id,
      })),
    };
  }

  async getServers() {
    return this.serverConnectionRepo
      .createQueryBuilder('conn')
      .leftJoinAndSelect('conn.license', 'license')
      .leftJoinAndSelect('license.owner', 'owner')
      .orderBy('conn.created_at', 'DESC')
      .getMany();
  }
}
