<?php
// app/services/TransmissionService.php

declare(strict_types=1);

namespace ScMedia\Services;

final class TransmissionService {
  private HttpClient $http;
  private SettingsService $settings;
  private ?LogService $logger;

  public function __construct(HttpClient $http, SettingsService $settings, ?LogService $logger = null) {
    $this->http = $http;
    $this->settings = $settings;
    $this->logger = $logger;
  }

  public function list(): array {
    $cfg = $this->getConfig();
    if (empty($cfg['enabled'])) return [];
    $res = $this->rpcRequest($cfg, 'torrent-get', [
      'fields' => ['id','name','totalSize','status','percentDone','downloadDir','labels','files'],
    ]);
    if (!$res['ok'] || !is_array($res['data'])) {
      return [];
    }
    $rows = is_array($res['data']['arguments']['torrents'] ?? null) ? $res['data']['arguments']['torrents'] : [];
    $out = [];
    foreach ($rows as $t) {
      if (!is_array($t)) continue;
      $files = is_array($t['files'] ?? null) ? $t['files'] : [];
      $fileCount = count($files);
      $contentType = ($fileCount > 1) ? 'folder' : 'file';
      $out[] = [
        'id' => (int)($t['id'] ?? 0),
        'name' => (string)($t['name'] ?? ''),
        'size_bytes' => (int)($t['totalSize'] ?? 0),
        'status' => $this->statusLabel((int)($t['status'] ?? 0), (float)($t['percentDone'] ?? 0)),
        'percent_done' => (float)($t['percentDone'] ?? 0),
        'path' => (string)($t['downloadDir'] ?? ''),
        'labels' => $t['labels'] ?? [],
        'source' => 'transmission',
        'file_count' => $fileCount,
        'content_type' => $contentType,
      ];
    }
    return $out;
  }

  public function test(array $cfg): array {
    $cfg = $this->normalizeConfig($cfg);
    $res = $this->rpcRequest($cfg, 'session-get', []);
    if (!$res['ok']) {
      $status = $res['status'] ?? null;
      if ($status === 401) {
        return ['ok' => false, 'error' => 'unauthorized'];
      }
      if ($status === 403) {
        return ['ok' => false, 'error' => 'forbidden'];
      }
      return ['ok' => false, 'error' => $res['error'] ?? 'request failed'];
    }
    return ['ok' => true];
  }

  public function detail(int $id): array {
    $cfg = $this->getConfig();
    if (empty($cfg['enabled'])) {
      return ['ok' => false, 'error' => 'disabled'];
    }
    $res = $this->rpcRequest($cfg, 'torrent-get', [
      'ids' => [$id],
      'fields' => [
        'id','name','totalSize','status','percentDone','downloadDir','labels',
        'rateDownload','rateUpload','addedDate','doneDate','eta','uploadedEver','downloadedEver',
        'files','fileStats'
      ],
    ]);
    if (!$res['ok'] || !is_array($res['data'])) {
      return ['ok' => false, 'error' => $res['error'] ?? 'rpc failed'];
    }
    $rows = is_array($res['data']['arguments']['torrents'] ?? null) ? $res['data']['arguments']['torrents'] : [];
    if (count($rows) === 0) {
      return ['ok' => false, 'error' => 'not found'];
    }
    $t = $rows[0];
    $files = is_array($t['files'] ?? null) ? $t['files'] : [];
    $stats = is_array($t['fileStats'] ?? null) ? $t['fileStats'] : [];
    $fileList = [];
    foreach ($files as $idx => $f) {
      if (!is_array($f)) continue;
      $stat = $stats[$idx] ?? [];
      $length = (int)($f['length'] ?? 0);
      $done = (int)($stat['bytesCompleted'] ?? 0);
      $pct = $length > 0 ? round(($done / $length) * 100, 1) : 0.0;
      $fileList[] = [
        'path' => (string)($f['name'] ?? ''),
        'size_bytes' => $length,
        'bytes_done' => $done,
        'percent_done' => $pct,
        'wanted' => !empty($stat['wanted']),
        'priority' => (int)($stat['priority'] ?? 0),
      ];
    }

    $core = [
      'id' => (int)($t['id'] ?? 0),
      'name' => (string)($t['name'] ?? ''),
      'status' => $this->statusLabel((int)($t['status'] ?? 0), (float)($t['percentDone'] ?? 0)),
      'percent_done' => (float)($t['percentDone'] ?? 0),
      'size_bytes' => (int)($t['totalSize'] ?? 0),
      'source' => 'transmission',
    ];

    $fields = [
      ['key' => 'download_dir', 'label' => 'Download dir', 'type' => 'text', 'value' => (string)($t['downloadDir'] ?? '')],
      ['key' => 'labels', 'label' => 'Labels', 'type' => 'list', 'value' => $t['labels'] ?? []],
      ['key' => 'rate_download', 'label' => 'Download speed', 'type' => 'speed', 'value' => (int)($t['rateDownload'] ?? 0)],
      ['key' => 'rate_upload', 'label' => 'Upload speed', 'type' => 'speed', 'value' => (int)($t['rateUpload'] ?? 0)],
      ['key' => 'added_date', 'label' => 'Added', 'type' => 'date', 'value' => (int)($t['addedDate'] ?? 0)],
      ['key' => 'done_date', 'label' => 'Completed', 'type' => 'date', 'value' => (int)($t['doneDate'] ?? 0)],
      ['key' => 'eta', 'label' => 'ETA', 'type' => 'seconds', 'value' => (int)($t['eta'] ?? 0)],
      ['key' => 'uploaded', 'label' => 'Uploaded', 'type' => 'bytes', 'value' => (int)($t['uploadedEver'] ?? 0)],
      ['key' => 'downloaded', 'label' => 'Downloaded', 'type' => 'bytes', 'value' => (int)($t['downloadedEver'] ?? 0)],
    ];

    return ['ok' => true, 'core' => $core, 'fields' => $fields, 'files' => $fileList, 'raw' => $t];
  }

  private function getConfig(): array {
    $all = $this->settings->getAll();
    $sources = $all['sources'] ?? [];
    $cfg = is_array($sources['transmission'] ?? null) ? $sources['transmission'] : [];
    return $this->normalizeConfig($cfg);
  }

  private function normalizeConfig(array $cfg): array {
    return [
      'enabled' => !empty($cfg['enabled']),
      'protocol' => (string)($cfg['protocol'] ?? 'http'),
      'host' => (string)($cfg['host'] ?? ''),
      'port' => (int)($cfg['port'] ?? 9091),
      'path' => (string)($cfg['path'] ?? '/transmission/rpc'),
      'username' => (string)($cfg['username'] ?? ''),
      'password' => (string)($cfg['password'] ?? ''),
    ];
  }

  private function rpcRequest(array $cfg, string $method, array $args): array {
    $url = $this->buildUrl($cfg);
    $this->logger?->log('debug', 'Transmission config', [
      'protocol' => $cfg['protocol'] ?? null,
      'host' => $cfg['host'] ?? null,
      'port' => $cfg['port'] ?? null,
      'path' => $cfg['path'] ?? null,
      'has_auth' => (($cfg['username'] ?? '') !== '' || ($cfg['password'] ?? '') !== ''),
    ]);
    $headers = $this->buildHeaders($cfg, null);
    $payload = ['method' => $method, 'arguments' => $args];

    $this->logger?->log('debug', 'Transmission RPC request', [
      'method' => $method,
      'url' => $this->sanitizeUrl($url),
    ]);

    $res = $this->http->postJson($url, $payload, $headers);
    if (($res['status'] ?? 0) === 409) {
      $sid = (string)($res['headers']['x-transmission-session-id'] ?? '');
      $this->logger?->log('debug', 'Transmission session id required', ['has_sid' => $sid !== '']);
      if ($sid !== '') {
        $headers = $this->buildHeaders($cfg, $sid);
        $res = $this->http->postJson($url, $payload, $headers);
      }
    }

    if (empty($res['ok']) || !is_array($res['data'])) {
      $this->logger?->log('warn', 'Transmission RPC failed', [
        'method' => $method,
        'status' => $res['status'] ?? null,
        'error' => $res['error'] ?? null,
      ]);
      return [
        'ok' => false,
        'error' => $res['error'] ?? 'rpc failed',
        'status' => $res['status'] ?? null,
      ];
    }

    if (isset($res['data']['result']) && $res['data']['result'] !== 'success') {
      $this->logger?->log('warn', 'Transmission RPC result not success', ['result' => $res['data']['result'] ?? null]);
    }
    return ['ok' => true, 'data' => $res['data']];
  }

  private function buildUrl(array $cfg): string {
    $host = $cfg['host'] !== '' ? $cfg['host'] : 'localhost';
    $path = $cfg['path'] !== '' ? $cfg['path'] : '/transmission/rpc';
    if ($path[0] !== '/') $path = '/' . $path;
    return $cfg['protocol'] . '://' . $host . ':' . $cfg['port'] . $path;
  }

  private function buildHeaders(array $cfg, ?string $sessionId): array {
    $headers = ['Content-Type: application/json'];
    if ($sessionId) {
      $headers[] = 'X-Transmission-Session-Id: ' . $sessionId;
    }
    if ($cfg['username'] !== '' || $cfg['password'] !== '') {
      $basic = base64_encode($cfg['username'] . ':' . $cfg['password']);
      $headers[] = 'Authorization: Basic ' . $basic;
    }
    return $headers;
  }

  private function statusLabel(int $status, float $percent): string {
    if ($percent >= 1.0) return 'completed';
    if ($status === 1 || $status === 2) return 'checking';
    if ($status === 3) return 'queued';
    if ($status === 4) return 'downloading';
    if ($status === 6) return 'seeding';
    if ($status === 0) return 'stopped';
    return 'unknown';
  }

  private function sanitizeUrl(string $url): string {
    return $url;
  }
}
