<?php

declare(strict_types=1);

namespace App\Domain\Sysapi\Contracts;

use Illuminate\Process\ProcessResult;

/**
 * Sysapi komutunun çalışma sonucu.
 *
 * Master plan'dan exit code semantiği:
 *   0 = ok
 *   1 = invalid input (whitelist/regex geçmedi)
 *   2 = preflight fail (dependency yok, permission yok)
 *   3 = execution fail (komut çalıştı ama başarısız)
 *   4 = rollback ok (hata oldu, geri alındı)
 *   5 = rollback fail (hata oldu + geri alınamadı — KRİTİK)
 */
final readonly class SysapiResult
{
    public function __construct(
        public bool $successful,
        public int $exitCode,
        public string $stdout,
        public string $stderr,
        /** @var array<string, mixed>|null Parsed JSON from stdout, null if not JSON */
        public ?array $data,
        public float $durationSeconds,
    ) {}

    /**
     * Laravel Process facade'ından üret.
     */
    public static function fromProcess(ProcessResult $process, float $durationSeconds = 0.0): self
    {
        $stdout = $process->output();
        $data = null;

        if ($stdout !== '') {
            $decoded = json_decode($stdout, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                $data = $decoded;
            }
        }

        return new self(
            successful: $process->successful(),
            exitCode: $process->exitCode() ?? -1,
            stdout: $stdout,
            stderr: $process->errorOutput(),
            data: $data,
            durationSeconds: $durationSeconds,
        );
    }

    /**
     * Test helper'ı — başarılı sonuç üret.
     *
     * `ok()` ismi instance metod ile çakıştığı için `success()` adıyla expose ediliyor.
     *
     * @param  array<string, mixed>  $data
     */
    public static function success(array $data = [], string $stdout = ''): self
    {
        return new self(
            successful: true,
            exitCode: 0,
            stdout: $stdout !== '' ? $stdout : json_encode($data, JSON_THROW_ON_ERROR),
            stderr: '',
            data: $data === [] ? null : $data,
            durationSeconds: 0.0,
        );
    }

    /**
     * Test helper'ı — başarısız sonuç üret.
     */
    public static function fail(int $exitCode, string $stderr, string $stdout = ''): self
    {
        return new self(
            successful: false,
            exitCode: $exitCode,
            stdout: $stdout,
            stderr: $stderr,
            data: null,
            durationSeconds: 0.0,
        );
    }

    public function ok(): bool
    {
        return $this->successful;
    }

    public function failed(): bool
    {
        return ! $this->successful;
    }

    /**
     * Audit log tablosuna yazılacak yapıyı döndürür.
     *
     * @return array<string, mixed>
     */
    public function toAuditLog(): array
    {
        return [
            'action' => 'sysapi',
            'outcome' => $this->successful ? 'success' : 'failure',
            'exit_code' => $this->exitCode,
            'duration_seconds' => $this->durationSeconds,
            'stderr' => $this->stderr ?: null,
            'error_category' => $this->errorCategory(),
        ];
    }

    /**
     * Hata türünü exit code'dan tahmin et.
     */
    public function errorCategory(): string
    {
        return match ($this->exitCode) {
            0 => 'ok',
            1 => 'invalid_input',
            2 => 'preflight_fail',
            3 => 'execution_fail',
            4 => 'rolled_back',
            5 => 'critical_rollback_fail',
            default => 'unknown',
        };
    }
}
