import { Injectable, Logger } from '@nestjs/common';
import { spawn } from 'child_process';
import path from 'path';
import { DbService } from './db.service';
import { EventsGateway } from './events.gateway';

@Injectable()
export class HandbrakeService {
  private logger = new Logger('HandbrakeService');

  constructor(
    private readonly eventsGateway: EventsGateway,
    private readonly db: DbService,
  ) {}

  processWithHandbrake(
    input: string,
    output: string,
    preset: string,
    taskId?: number,
  ): Promise<boolean> {
    return new Promise((resolve, reject) => {
      try {
        const inputName = path.basename(input);
        const outputName = path.basename(output);
        let progressStarted = false;
        let lastPercent = 0;

        const hb = spawn('HandBrakeCLI', [
          '-i',
          input,
          '-o',
          output,
          '--preset',
          preset,
        ]);

        hb.stdout.on('data', (data) => {
          const str = data.toString();
          this.logger.debug(`HandBrake stdout: ${str}`);
          console.log('[STDOUT]', str);
          // Parse progress from stdout - try multiple patterns
          let progressMatch = str.match(
            /Encoding: task \d+ of \d+, (\d+(?:\.\d+)?)\s*%/,
          );
          if (!progressMatch) {
            // Try alternative pattern
            progressMatch = str.match(/(\d+(?:\.\d+)?)\s*%/);
          }
          if (progressMatch) {
            const percent = Math.round(parseFloat(progressMatch[1]));
            console.log(
              `[MATCH] Found progress: ${percent}%, lastPercent: ${lastPercent}, taskId: ${taskId}`,
            );
            if (percent !== lastPercent) {
              lastPercent = percent;
              progressStarted = true;

              console.log(`[UPDATE] Progress ${percent}% for task ${taskId}`);

              // Update task progress if we have a task ID
              if (taskId) {
                console.log(
                  `[DB] Updating task ${taskId} progress to ${percent}%`,
                );
                this.db.updateTask(taskId, { progress: percent });
                console.log(`[DB] Update complete`);
              } else {
                console.warn('[WARN] No taskId provided!');
              }

              // Emit progress update
              console.log(
                `[WS] Emitting progress event for task ${taskId}: ${percent}%`,
              );
              this.eventsGateway.emitTaskUpdate({
                type: 'progress',
                taskId,
                task: 'handbrake',
                input,
                output,
                preset,
                progress: percent,
              });
              console.log(`[WS] Emit complete`);
            }
          }
          this.logger.log(str);
        });

        hb.stderr.on('data', (data) => {
          const str = data.toString();
          this.logger.debug(`HandBrake stderr: ${str}`);
          console.log('[STDERR]', str);
          // Parse progress from stderr as fallback - try multiple patterns
          let progressMatch = str.match(
            /Encoding: task \d+ of \d+, (\d+(?:\.\d+)?)\s*%/,
          );
          if (!progressMatch) {
            // Try alternative pattern
            progressMatch = str.match(/(\d+(?:\.\d+)?)\s*%/);
          }
          if (progressMatch && !progressStarted) {
            const percent = Math.round(parseFloat(progressMatch[1]));
            console.log(
              `[STDERR MATCH] Found progress: ${percent}%, lastPercent: ${lastPercent}, taskId: ${taskId}`,
            );
            if (percent !== lastPercent) {
              lastPercent = percent;

              console.log(
                `[STDERR UPDATE] Progress ${percent}% for task ${taskId}`,
              );

              if (taskId) {
                console.log(
                  `[STDERR DB] Updating task ${taskId} progress to ${percent}%`,
                );
                this.db.updateTask(taskId, { progress: percent });
                console.log(`[STDERR DB] Update complete`);
              } else {
                console.warn('[STDERR WARN] No taskId provided!');
              }

              console.log(
                `[STDERR WS] Emitting progress event for task ${taskId}: ${percent}%`,
              );
              this.eventsGateway.emitTaskUpdate({
                type: 'progress',
                taskId,
                task: 'handbrake',
                input,
                output,
                preset,
                progress: percent,
              });
              console.log(`[STDERR WS] Emit complete`);
            }
          }
          this.logger.error(str);
        });

        hb.on('close', (code) => {
          if (code === 0) {
            this.logger.log(
              `Completed "${outputName}" with preset "${preset}"`,
            );

            // Final progress update
            if (taskId) {
              this.db.updateTask(taskId, { progress: 100 });
            }

            this.eventsGateway.emitTaskUpdate({
              type: 'completed',
              taskId,
              task: 'handbrake',
              input,
              output,
              preset,
              success: true,
            });
            resolve(true);
          } else {
            this.logger.error(`HandBrakeCLI exited with code ${code}`);

            this.eventsGateway.emitTaskUpdate({
              type: 'failed',
              taskId,
              task: 'handbrake',
              input,
              output,
              preset,
              success: false,
              error: `Exit code ${code}`,
            });
            reject(new Error(`HandBrakeCLI exited with code ${code}`));
          }
        });
      } catch (err) {
        this.logger.error(
          `Exception in processWithHandbrake: ${err && err.message ? err.message : err}`,
        );
        reject(err);
      }
    });
  }

  getPresetList(): Promise<string[]> {
    return new Promise((resolve, reject) => {
      const hb = spawn('HandBrakeCLI', ['--preset-list']);
      let output = '';
      hb.stdout.on('data', (data) => {
        output += data.toString();
      });
      hb.stderr.on('data', (data) => {
        output += data.toString();
      });
      hb.on('close', (code) => {
        if (code === 0) {
          // Parse the output to extract presets
          const lines = output.split('\n');
          const presets: string[] = [];

          for (const line of lines) {
            // Preset names start with exactly 4 spaces (not 8 for descriptions)
            if (
              line.startsWith('    ') &&
              !line.startsWith('        ') &&
              line.trim().length > 0
            ) {
              presets.push(line.trim());
            }
          }
          resolve(presets);
        } else {
          this.logger.error('Error getting preset list');
          resolve([]);
        }
      });
    });
  }
}
