<?php
// app/services/MediaApplyService.php

declare(strict_types=1);

namespace ScMedia\Services;

final class MediaApplyService {
  private MediaLibraryService $media;
  private MkvToolnixService $mkvtoolnix;
  private JobsService $jobs;
  private MetadataService $metadata;
  private ExportService $export;

  public function __construct(
    MediaLibraryService $media,
    MkvToolnixService $mkvtoolnix,
    JobsService $jobs,
    MetadataService $metadata,
    ExportService $export
  ) {
    $this->media = $media;
    $this->mkvtoolnix = $mkvtoolnix;
    $this->jobs = $jobs;
    $this->metadata = $metadata;
    $this->export = $export;
  }

  public function applyTab(string $tab, int $jobId): array {
    $items = $this->media->listTab($tab);
    $files = $this->expandFiles($tab, $items);

    $total = count($files);
    $this->jobs->setProgress($jobId, 0, max(1, $total));

    $done = 0;
    $rename = 0;
    $delete = 0;
    $convert = 0;
    $errors = 0;
    $seriesExported = [];

    foreach ($files as $f) {
      if ($this->jobs->cancelIfRequested($jobId)) {
        $this->jobs->log($jobId, 'warn', 'Apply canceled by user');
        return [
          'files' => $total,
          'renamed' => $rename,
          'deleted' => $delete,
          'converted' => $convert,
          'errors' => $errors,
          'canceled' => true,
        ];
      }
      $done++;
      $this->jobs->setProgress($jobId, $done, $total);

      $path = (string)($f['abs_path'] ?? '');
      if ($path === '') continue;

      $plan = $this->media->buildEdits($path);

      if (!empty($plan['convert'])) {
        $res = $this->convertFile($path);
        if (!$res['ok']) {
          $errors++;
          $this->jobs->log($jobId, 'error', "Convert failed: {$path} | {$res['error']}");
        } else {
          $convert++;
          $this->jobs->log($jobId, 'info', "Converted: {$path} -> {$res['dest']}");
          $path = $res['dest'];
        }
      }

      if (count($plan['delete']) > 0 || count($plan['rename']) > 0) {
        $res = $this->mkvtoolnix->applyTrackEdits($path, $plan['rename'], $plan['delete']);
        if (!$res['ok']) {
          $errors++;
          $this->jobs->log($jobId, 'error', "Apply failed: {$path} | {$res['error']}");
        } else if (!empty($res['changed'])) {
          $rename += count($plan['rename']);
          $delete += count($plan['delete']);
          $this->jobs->log($jobId, 'info', "Applied: {$path} (rename " . count($plan['rename']) . ", delete " . count($plan['delete']) . ")");
        }
      }

      $exported = $this->maybeExportMeta($f, $seriesExported);
      foreach ($exported as $expId => $res) {
        if (!empty($res['ok'])) {
          $this->jobs->log($jobId, 'info', "Exported {$expId}: " . ($res['path'] ?? $path));
        } else if (!empty($res['error'])) {
          $this->jobs->log($jobId, 'warn', "Export {$expId} failed: " . ($res['error'] ?? 'error'));
        }
      }
    }

    return [
      'files' => $total,
      'renamed' => $rename,
      'deleted' => $delete,
      'converted' => $convert,
      'errors' => $errors,
    ];
  }

  private function expandFiles(string $tab, array $items): array {
    if ($tab !== 'series') return $items;
    $out = [];
    foreach ($items as $s) {
      $key = (string)($s['series_key'] ?? '');
      if ($key === '') continue;
      $files = $this->media->getSeriesFiles($key);
      foreach ($files as $f) $out[] = $f;
    }
    return $out;
  }

  private function convertFile(string $src): array {
    $dir = dirname($src);
    $base = pathinfo($src, PATHINFO_FILENAME);
    $dest = $dir . '/' . $base . '.mkv';
    if (is_file($dest)) {
      $dest = $dir . '/' . $base . '_conv.mkv';
    }

    $res = $this->mkvtoolnix->convertToMkv($src, $dest);
    if (!$res['ok']) return $res;

    $meta = $this->mkvtoolnix->readFileData($dest);
    $info = (is_array($meta) && isset($meta['mkvmerge']['data'])) ? $meta['mkvmerge']['data'] : null;
    $this->media->updateFilePath($src, $dest, $info);

    return ['ok' => true, 'dest' => $dest];
  }

  private function maybeExportMeta(array $file, array &$seriesExported): array {
    $enabled = $this->export->getEnabledExporters();
    if (count($enabled) === 0) return [];

    $kind = (string)($file['kind'] ?? 'movie');
    if ($kind === 'series') {
      $seriesKey = (string)($file['series_key'] ?? '');
      if ($seriesKey === '' || isset($seriesExported[$seriesKey])) {
        return [];
      }
      $metaRow = $this->metadata->getSubjectMeta('series', $seriesKey);
      if (!is_array($metaRow)) return [];
      $display = $this->metadata->formatDisplay($metaRow);
      $payload = $this->buildExportPayload($display);
      if ($payload['title'] === '' && $payload['original_title'] === '') return [];
      $seriesPath = $this->resolveSeriesPath($file);
      $seriesExported[$seriesKey] = true;
      return $this->export->exportSeries($seriesPath, $payload);
    }

    $path = (string)($file['abs_path'] ?? '');
    if ($path === '') return [];
    $metaRow = $this->metadata->getSubjectMeta('movie', $path);
    if (!is_array($metaRow)) return [];
    $display = $this->metadata->formatDisplay($metaRow);
    $payload = $this->buildExportPayload($display);
    if ($payload['title'] === '' && $payload['original_title'] === '') return [];
    return $this->export->exportMovie($path, $payload);
  }

  private function buildExportPayload(array $display): array {
    $meta = is_array($display['meta'] ?? null) ? $display['meta'] : [];
    $provider = (string)($meta['provider'] ?? '');
    $providerId = (string)($meta['provider_id'] ?? '');
    $providerUrl = '';
    if ($provider !== '' && $providerId !== '') {
      $providerUrl = $this->metadata->buildProviderUrl($provider, $providerId);
    }
    return [
      'title' => (string)($display['title_display'] ?? ''),
      'original_title' => (string)($display['title_original'] ?? ''),
      'year' => $display['year'] ?? null,
      'provider' => $provider,
      'provider_id' => $providerId,
      'provider_url' => $providerUrl,
    ];
  }

  private function resolveSeriesPath(array $file): string {
    $abs = (string)($file['abs_path'] ?? '');
    $rel = (string)($file['rel_path'] ?? '');
    $seriesKey = (string)($file['series_key'] ?? '');
    if ($abs !== '' && $rel !== '' && str_ends_with($abs, $rel) && $seriesKey !== '') {
      $root = substr($abs, 0, strlen($abs) - strlen($rel));
      return rtrim($root, '/') . '/' . $seriesKey;
    }
    return $abs !== '' ? dirname($abs) : '';
  }
}
