<?php

namespace SHServ\Controllers;

use SHServ\Models\Devices;
use SHServ\Tools\FirmwareCatalog;

class FirmwareRESTAPIController extends \SHServ\Middleware\Controller {

	public function firmwares_list() {
		$catalog = new FirmwareCatalog();
		$all     = $catalog->getAll();

		$firmwares = array_values(array_map(function ($entry) {
			return $entry['manifest'];
		}, $all));

		return $this->utils()->response_success([
			'firmwares' => $firmwares,
			'total'     => count($firmwares),
		]);
	}

	public function firmware_detail($firmware_id) {
		$catalog = new FirmwareCatalog();
		$entry   = $catalog->getById($firmware_id);

		if (!$entry) {
			return $this->utils()->response_error('firmware_not_found');
		}

		return $this->utils()->response_success([
			'firmware' => $entry['manifest'],
		]);
	}

	public function firmware_download($firmware_id) {
		$catalog = new FirmwareCatalog();
		$binPath = $catalog->getBinPath($firmware_id);

		if (!$binPath) {
			return $this->utils()->response_error('firmware_not_found');
		}

		$entry    = $catalog->getById($firmware_id);
		$filename = $entry['manifest']['bin_filename'] ?? 'firmware.bin';

		header('Content-Type: application/octet-stream');
		header('Content-Disposition: attachment; filename="' . $filename . '"');
		header('Content-Length: ' . filesize($binPath));
		readfile($binPath);

		// cleanup
		$tempDir = dirname($binPath);
		if (strpos($tempDir, sys_get_temp_dir()) === 0) {
			@unlink($binPath);
			@rmdir($tempDir);
		}
		exit;
	}

	public function firmware_refresh() {
		$catalog = new FirmwareCatalog();
		$catalog->scan();

		return $this->utils()->response_success();
	}

	public function device_firmware_compatibility($device_id) {
		$device_id = intval($device_id);
		if ($device_id < 1) {
			return $this->utils()->response_error('invalid_id', ['device_id']);
		}

		$devices_model = new Devices();
		$device = $devices_model->by_id($device_id);

		if (!$device) {
			return $this->utils()->response_error('device_not_found');
		}

		$about = $device->device_api()->get_about();
		if (($about['http_code'] ?? 0) !== 200 || !is_array($about['data'] ?? null)) {
			return $this->utils()->response_error('device_request_fail');
		}

		$catalog    = new FirmwareCatalog();
		$compatible = $catalog->findCompatible($about['data']);

		return $this->utils()->response_success([
			'compatible'      => $compatible,
			'current_version'   => $about['data']['firmware_version'] ?? 'unknown',
			'current_platform'  => $about['data']['platform'] ?? null,
			'current_channels'  => $about['data']['channels'] ?? null,
		]);
	}

	public function device_update_firmware($device_id, $firmware_id) {
		$device_id = intval($device_id);
		if ($device_id < 1) {
			return $this->utils()->response_error('invalid_id', ['device_id']);
		}

		$devices_model = new Devices();
		$device = $devices_model->by_id($device_id);

		if (!$device) {
			return $this->utils()->response_error('device_not_found');
		}

		$catalog = new FirmwareCatalog();
		$binPath = $catalog->getBinPath($firmware_id);

		if (!$binPath) {
			return $this->utils()->response_error('firmware_not_found');
		}

		// Проверка совместимости
		$about = $device->device_api()->get_about();
		if (($about['http_code'] ?? 0) !== 200 || !is_array($about['data'] ?? null)) {
			$this->cleanupBin($binPath);
			return $this->utils()->response_error('device_request_fail');
		}

		$compatible = $catalog->findCompatible($about['data']);
		$ids = array_column($compatible, 'id');
		if (!in_array($firmware_id, $ids, true)) {
			$this->cleanupBin($binPath);
			return $this->utils()->response_error('firmware_not_compatible');
		}

		// Push OTA
		$result = $device->device_api()->updateFirmware($binPath);
		$this->cleanupBin($binPath);

		if (($result['http_code'] ?? 0) !== 200) {
			return $this->utils()->response_error('ota_failed', [], [
				'device_msg' => $result['error'] ?? '',
			]);
		}

		return $this->utils()->response_success([
			'device_msg' => $result['raw'] ?? 'Update OK',
		]);
	}

	// ------------------------------------------------------------------------
	// Helpers
	// ------------------------------------------------------------------------

	private function cleanupBin(string $binPath): void {
		$tempDir = dirname($binPath);
		if (strpos($tempDir, sys_get_temp_dir()) === 0) {
			@unlink($binPath);
			@rmdir($tempDir);
		}
	}
}
