<?php
// app/controllers/sources.php

declare(strict_types=1);

use ScMedia\Http\Response;
use ScMedia\Http\Router;
use ScMedia\Services\SourcesService;
use ScMedia\Services\TransmissionService;

final class SourcesController extends BaseController {
  public static function register(Router $router, Container $container): void {
    $self = new self($container);
    $router->add('POST', '/api/sources/list', fn() => $self->listSources());
    $router->add('GET', '/api/sources/detail', fn() => $self->getDetail());
    $router->add('POST', '/api/sources/test', fn() => $self->testSource());
    $router->add('GET', '/api/sources/preview', fn() => $self->getPreview());
    $router->add('POST', '/api/sources/approve', fn() => $self->approveSource());
  }

  private function listSources(): void {
    /** @var SourcesService $sources */
    $sources = $this->services()['sources'];
    [$page, $perPage, $sort, $dir, $filters] = table_body_params(50, 500);
    $items = $sources->list();
    $items = apply_filters_array($items, $filters, [
      'source' => 'source',
      'type' => 'content_type',
      'name' => 'name',
      'size' => 'size_bytes',
      'status' => 'status',
      'progress' => fn($it) => (float)($it['percent_done'] ?? 0) * 100,
    ]);
    $sortMap = ['name' => 'name', 'size' => 'size_bytes', 'status' => 'status'];
    $sortKey = $sortMap[$sort] ?? $sort;
    if ($sortKey !== '') {
      usort($items, function ($a, $b) use ($sortKey, $dir) {
        $av = $a[$sortKey] ?? null;
        $bv = $b[$sortKey] ?? null;
        if ($av === $bv) return 0;
        if (strtolower($dir) === 'desc') return ($av < $bv) ? 1 : -1;
        return ($av < $bv) ? -1 : 1;
      });
    }
    [$slice, $total] = paginate_array($items, $page, $perPage);
    Response::json(['ok' => true, 'data' => [
      'items' => $slice,
      'total' => $total,
      'page' => $page,
      'per_page' => $perPage,
    ]]);
  }

  private function getDetail(): void {
    $source = (string)($_GET['source'] ?? '');
    $id = (int)($_GET['id'] ?? 0);
    if ($source === '' || $id <= 0) {
      Response::json(['ok' => false, 'error' => ['code' => 'PARAMS_REQUIRED', 'message' => 'source and id required']], 400);
      return;
    }

    if ($source === 'transmission') {
      /** @var TransmissionService $transmission */
      $transmission = $this->services()['transmission'];
      $settings = $this->settings();
      $res = $transmission->detail($id);
      if (empty($res['ok'])) {
        Response::json(['ok' => false, 'error' => ['code' => 'SOURCE_FAILED', 'message' => $res['error'] ?? 'failed']], 400);
        return;
      }
      $all = $settings->getAll();
      $sources = $all['sources'] ?? [];
      $cfg = is_array($sources['transmission'] ?? null) ? $sources['transmission'] : [];
      $display = is_array($cfg['display_fields'] ?? null) ? $cfg['display_fields'] : [];
      if (count($display) > 0) {
        $res['fields'] = array_values(array_filter($res['fields'] ?? [], function ($f) use ($display) {
          $key = (string)($f['key'] ?? '');
          return $key !== '' && in_array($key, $display, true);
        }));
      }
      Response::json(['ok' => true, 'data' => [
        'core' => $res['core'] ?? [],
        'fields' => $res['fields'] ?? [],
        'files' => $res['files'] ?? [],
        'preview' => $this->buildTransmissionPreview($res),
        'raw' => $res['raw'] ?? null,
      ]]);
      return;
    }

    Response::json(['ok' => false, 'error' => ['code' => 'UNKNOWN_SOURCE', 'message' => 'unknown source']], 400);
  }

  private function testSource(): void {
    /** @var TransmissionService $transmission */
    $transmission = $this->services()['transmission'];
    $logger = $this->logger();
    $body = read_json_body();
    $cfg = is_array($body['transmission'] ?? null) ? $body['transmission'] : [];
    try {
      $res = $transmission->test($cfg);
      if (empty($res['ok'])) {
        $logger->log('warn', 'Transmission test failed', ['error' => $res['error'] ?? 'failed']);
        Response::json(['ok' => false, 'error' => ['code' => 'TEST_FAILED', 'message' => $res['error'] ?? 'failed']], 400);
        return;
      }
      $logger->log('info', 'Transmission test ok');
      Response::json(['ok' => true]);
    } catch (Throwable $e) {
      $logger->log('error', 'Transmission test exception', ['error' => $e->getMessage()]);
      Response::json(['ok' => false, 'error' => ['code' => 'TEST_EXCEPTION', 'message' => $e->getMessage()]], 500);
    }
  }

  private function getPreview(): void {
    $source = (string)($_GET['source'] ?? '');
    $id = (int)($_GET['id'] ?? 0);
    if ($source === '' || $id <= 0) {
      Response::json(['ok' => false, 'error' => ['code' => 'PARAMS_REQUIRED', 'message' => 'source and id required']], 400);
      return;
    }

    if ($source === 'transmission') {
      /** @var TransmissionService $transmission */
      $transmission = $this->services()['transmission'];
      $detail = $transmission->detail($id);
      if (empty($detail['ok'])) {
        Response::json(['ok' => false, 'error' => ['code' => 'SOURCE_FAILED', 'message' => $detail['error'] ?? 'failed']], 400);
        return;
      }
      $preview = $this->buildTransmissionPreview($detail);
      Response::json(['ok' => true, 'data' => $preview]);
      return;
    }

    Response::json(['ok' => false, 'error' => ['code' => 'UNKNOWN_SOURCE', 'message' => 'unknown source']], 400);
  }

  private function approveSource(): void {
    $body = read_json_body();
    $source = (string)($body['source'] ?? '');
    $id = (int)($body['id'] ?? 0);
    if ($source === '' || $id <= 0) {
      Response::json(['ok' => false, 'error' => ['code' => 'PARAMS_REQUIRED', 'message' => 'source and id required']], 400);
      return;
    }
    /** @var \ScMedia\Services\JobsService $jobs */
    $jobs = $this->services()['jobs'];
    $logger = $this->logger();
    $payload = ['source' => $source, 'id' => $id];
    $jobId = $jobs->create('task', "Source approve: {$source} #{$id}", $payload);
    $logger->log('info', 'Source approved', ['source' => $source, 'id' => $id, 'job_id' => $jobId]);
    Response::json(['ok' => true, 'data' => ['job_id' => $jobId]]);
  }

  private function buildTransmissionPreview(array $detail): array {
    $core = $detail['core'] ?? [];
    $files = is_array($detail['files'] ?? null) ? $detail['files'] : [];
    $typeInfo = $this->detectSourceType($files);
    $episodes = $this->detectSeriesEpisodes($files);
    $current = [
      'name' => (string)($core['name'] ?? ''),
      'kind' => $typeInfo['kind'],
      'structure' => $typeInfo['structure'],
      'file_count' => count($files),
      'size_bytes' => (int)($core['size_bytes'] ?? 0),
      'episodes' => $episodes,
    ];
    $planned = $current;
    $planned['note'] = 'Pending rules';
    return ['current' => $current, 'planned' => $planned];
  }

  private function detectSourceType(array $files): array {
    $structure = 'file';
    $kind = 'movie';
    $hasVideoTs = false;
    $hasBdmv = false;
    foreach ($files as $f) {
      $path = (string)($f['path'] ?? '');
      if ($path === '') continue;
      if (stripos($path, 'VIDEO_TS/') !== false || stripos($path, '/VIDEO_TS/') !== false) $hasVideoTs = true;
      if (stripos($path, 'BDMV/') !== false || stripos($path, '/BDMV/') !== false) $hasBdmv = true;
    }
    if ($hasBdmv) {
      $structure = 'bluray';
    } elseif ($hasVideoTs) {
      $structure = 'dvd';
    } elseif (count($files) > 1) {
      $structure = 'folder';
    }

    $episodes = $this->detectSeriesEpisodes($files);
    if (count($episodes) > 0) {
      $kind = 'series';
    }

    return ['structure' => $structure, 'kind' => $kind];
  }

  private function detectSeriesEpisodes(array $files): array {
    $out = [];
    foreach ($files as $f) {
      $path = (string)($f['path'] ?? '');
      if ($path === '') continue;
      if (preg_match('/S(\\d{1,2})E(\\d{1,2})/i', $path, $m)) {
        $season = (int)$m[1];
        $episode = (int)$m[2];
        $key = sprintf('S%02dE%02d', $season, $episode);
        $out[$key] = ['season' => $season, 'episode' => $episode];
      }
    }
    ksort($out);
    return array_values($out);
  }
}
