<?php
// app/controllers/media.php

declare(strict_types=1);

use ScMedia\Http\Response;
use ScMedia\Http\Router;
use ScMedia\Services\MediaLibraryService;
use ScMedia\Services\SettingsService;

final class MediaController extends BaseController {
  public static function register(Router $router, Container $container): void {
    $self = new self($container);
    $router->add('POST', '/api/media/list', fn() => $self->listMedia());
    $router->add('GET', '/api/media/series', fn() => $self->seriesDetail());
    $router->add('GET', '/api/media/file', fn() => $self->fileDetail());
    $router->add('GET', '/api/media/rules', fn() => $self->getRules());
    $router->add('GET', '/api/media/dry-run', fn() => $self->dryRun());
    $router->add('POST', '/api/media/rules', fn() => $self->saveRules());
    $router->add('POST', '/api/media/apply', fn() => $self->applyChanges());
  }

  private function listMedia(): void {
    /** @var MediaLibraryService $media */
    $media = $this->services()['media_library'];
    $logger = $this->logger();
    [$page, $perPage, $sort, $dir, $filters, $params] = table_body_params(50, 500);
    $tab = (string)($params['tab'] ?? 'movies');
    $tab = in_array($tab, ['movies','series','needs_mkv'], true) ? $tab : 'movies';
    $result = $media->listTabPaged($tab, $page, $perPage, $sort, $dir);
    $items = $result['items'] ?? [];
    $total = (int)($result['total'] ?? 0);
    $logger->log('debug', 'Media list', ['tab' => $tab, 'count' => count($items), 'page' => $page]);
    Response::json(['ok' => true, 'data' => [
      'items' => $items,
      'total' => $total,
      'page' => $page,
      'per_page' => $perPage,
    ]]);
  }

  private function seriesDetail(): void {
    /** @var MediaLibraryService $media */
    $media = $this->services()['media_library'];
    /** @var \ScMedia\Services\MetadataService $metadata */
    $metadata = $this->services()['metadata'];
    $logger = $this->logger();
    $key = (string)($_GET['key'] ?? '');
    if ($key === '') {
      Response::json(['ok' => false, 'error' => ['code' => 'KEY_REQUIRED', 'message' => 'key required']], 400);
      return;
    }
    $data = $media->getSeriesFiles($key);
    $metaRow = $metadata->getSubjectMeta('series', $key);
    $display = $metadata->formatDisplay($metaRow);
    $meta = is_array($display['meta'] ?? null) ? $display['meta'] : [];
    $meta['subject_kind'] = 'series';
    $meta['subject_key'] = $key;
    $meta['title_display'] = $display['title_display'];
    $meta['title_original'] = $display['title_original'];
    $meta['year'] = $display['year'];
    $logger->log('debug', 'Series detail', ['series_key' => $key, 'files' => count($data)]);
    Response::json(['ok' => true, 'data' => ['files' => $data, 'meta' => $meta]]);
  }

  private function fileDetail(): void {
    /** @var MediaLibraryService $media */
    $media = $this->services()['media_library'];
    $logger = $this->logger();
    $path = (string)($_GET['path'] ?? '');
    $id = (int)($_GET['id'] ?? 0);
    if ($path === '' && $id > 0) {
      $db = $this->db();
      $row = $db->fetchOne("SELECT abs_path FROM media_files WHERE id=:id", [':id' => $id]);
      $path = $row ? (string)$row['abs_path'] : '';
    }
    if ($path === '') {
      Response::json(['ok' => false, 'error' => ['code' => 'PATH_REQUIRED', 'message' => 'path or id required']], 400);
      return;
    }
    $data = $media->getFileDetail($path);
    if (empty($data['ok'])) {
      $logger->log('warn', 'Media file detail not found', ['path' => $path, 'id' => $id]);
      Response::json(['ok' => false, 'error' => ['code' => 'NOT_FOUND', 'message' => (string)($data['error'] ?? 'not found')]], 404);
      return;
    }
    $logger->log('debug', 'Media file detail', ['path' => $path, 'id' => $id]);
    Response::json(['ok' => true, 'data' => $data]);
  }

  private function getRules(): void {
    /** @var MediaLibraryService $media */
    $media = $this->services()['media_library'];
    Response::json(['ok' => true, 'data' => $media->getRules()]);
  }

  private function dryRun(): void {
    /** @var MediaLibraryService $media */
    $media = $this->services()['media_library'];
    $logger = $this->logger();
    $tab = (string)($_GET['tab'] ?? 'movies');
    $tab = in_array($tab, ['movies','series','needs_mkv'], true) ? $tab : 'movies';
    $data = $media->dryRun($tab);
    $logger->log('info', 'Dry run computed', ['tab' => $tab, 'files' => $data['files'] ?? null]);
    Response::json(['ok' => true, 'data' => $data]);
  }

  private function saveRules(): void {
    /** @var SettingsService $settings */
    $settings = $this->settings();
    $logger = $this->logger();
    $body = read_json_body();
    $rules = is_array($body['media_rules'] ?? null) ? $body['media_rules'] : [];
    $payload = ['media_rules' => $rules];
    if (isset($body['if_revision'])) {
      $payload['if_revision'] = (int)$body['if_revision'];
    }
    try {
      $rev = $settings->saveBulk($payload);
      $logger->log('info', 'Media rules saved', ['revision' => $rev]);
      Response::json(['ok' => true, 'data' => ['settings_revision' => $rev]]);
    } catch (Throwable $e) {
      $logger->log('error', 'Media rules save failed', ['error' => $e->getMessage()]);
      Response::json(['ok' => false, 'error' => ['code' => 'SAVE_FAILED', 'message' => $e->getMessage()]], 400);
    }
  }

  private function applyChanges(): void {
    /** @var \ScMedia\Services\MediaApplyService $apply */
    $apply = $this->services()['media_apply'];
    /** @var \ScMedia\Services\JobsService $jobs */
    $jobs = $this->services()['jobs'];
    $logger = $this->logger();
    $settings = $this->settings();

    $body = read_json_body();
    $tab = (string)($body['tab'] ?? 'movies');
    $tab = in_array($tab, ['movies','series','needs_mkv'], true) ? $tab : 'movies';

    $bg = $settings->getAll()['background'] ?? [];
    if (!empty($bg['paused'])) {
      Response::json(['ok' => false, 'error' => 'Background jobs paused'], 409);
      return;
    }

    $jobId = $jobs->create('apply', 'Apply media changes', ['tab' => $tab]);
    try {
      $jobs->start($jobId);
      $logger->log('info', 'Apply started', ['job_id' => $jobId, 'tab' => $tab]);
      $result = $apply->applyTab($tab, $jobId);
      $status = $jobs->getStatus($jobId);
      if ($status !== 'canceled') {
        $jobs->finish($jobId);
        $logger->log('info', 'Apply finished', ['job_id' => $jobId, 'tab' => $tab, 'result' => $result]);
      } else {
        $logger->log('warn', 'Apply canceled', ['job_id' => $jobId, 'tab' => $tab]);
      }
      Response::json(['ok' => true, 'job_id' => $jobId, 'result' => $result, 'status' => $status]);
    } catch (Throwable $e) {
      $jobs->log($jobId, 'error', $e->getMessage());
      $jobs->fail($jobId, $e->getMessage());
      $logger->log('error', 'Apply failed', ['job_id' => $jobId, 'tab' => $tab, 'error' => $e->getMessage()]);
      Response::json(['ok' => false, 'error' => $e->getMessage()], 500);
    }
  }
}
