import { Injectable, NotFoundException, InternalServerErrorException, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ServerConnection } from '../../entities/server-connection.entity';
import { ServerConfig } from '../../entities/server-config.entity';
import { NatsService } from '../../services/nats.service';
import { UpdateServerConfigDto } from './dto/update-config.dto';
import { DeployServerDto } from './dto/deploy-server.dto';

@Injectable()
export class ServersService {
  private readonly logger = new Logger(ServersService.name);

  constructor(
    @InjectRepository(ServerConnection)
    private readonly connectionRepo: Repository<ServerConnection>,
    @InjectRepository(ServerConfig)
    private readonly configRepo: Repository<ServerConfig>,
    private readonly natsService: NatsService,
  ) {}

  /**
   * Get server connection and config for a license.
   * Returns null fields if no server has been set up yet.
   */
  async getServer(licenseId: string) {
    const connection = await this.connectionRepo.findOne({
      where: { license_id: licenseId },
    });

    const config = await this.configRepo.findOne({
      where: { license_id: licenseId },
    });

    return {
      connection: connection || null,
      config: config || null,
      setup_required: !connection || !config,
    };
  }

  /**
   * Update server configuration
   */
  async updateConfig(licenseId: string, dto: UpdateServerConfigDto) {
    const config = await this.configRepo.findOne({
      where: { license_id: licenseId },
    });

    if (!config) {
      throw new NotFoundException('Server config not found');
    }

    // Apply updates
    Object.assign(config, dto);
    config.updated_at = new Date();

    return await this.configRepo.save(config);
  }

  /**
   * Send a console command to the server via NATS
   */
  async sendCommand(licenseId: string, command: string) {
    try {
      await this.natsService.sendServerCommand(licenseId, 'command', { command });
      this.logger.log(`Console command dispatched for license ${licenseId}: ${command}`);
    } catch (err) {
      this.logger.error(`Failed to dispatch console command for license ${licenseId}: ${(err as Error).message}`);
      throw new InternalServerErrorException('Failed to dispatch command to server');
    }
    return { success: true, message: 'Command dispatched' };
  }

  /**
   * Start the server via NATS
   */
  async startServer(licenseId: string) {
    await this.natsService.sendServerCommand(licenseId, 'start');
    return { message: 'Start command sent' };
  }

  /**
   * Stop the server via NATS
   */
  async stopServer(licenseId: string) {
    await this.natsService.sendServerCommand(licenseId, 'stop');
    return { message: 'Stop command sent' };
  }

  /**
   * Restart the server via NATS
   */
  async restartServer(licenseId: string) {
    await this.natsService.sendServerCommand(licenseId, 'restart');
    return { message: 'Restart command sent' };
  }

  /**
   * Deploy Rust server via companion agent
   */
  async deployServer(licenseId: string, dto: DeployServerDto) {
    await this.natsService.sendDeployCommand(licenseId, { ...dto });
    return { message: 'Deployment started' };
  }
}
