<?php

namespace App\Domain\Workflow\Services;

use App\Domain\Experiment\Models\Experiment;
use App\Domain\Experiment\Models\PlaybookStep;

/**
 * Renders a markdown "provenance" block summarising an experiment's
 * execution trail — the triggering signal, the agents that ran, their
 * outputs, the cost, and the elapsed time. Intended for embedding in PR
 * bodies, Slack notifications, or audit exports.
 *
 * Pattern borrowed from prilog.ai: the artifact carries its own history
 * inline, so a reviewer reading the PR can see why this change exists
 * without leaving the page.
 */
class ArtifactProvenanceFormatter
{
    /**
     * Render a markdown provenance block for the given experiment.
     */
    public function forExperiment(Experiment $experiment): string
    {
        $experiment->loadMissing(['signals', 'playbookSteps.agent']);

        $lines = [];
        $lines[] = '## Provenance';
        $lines[] = '';
        $lines[] = '_Generated by FleetQ — this PR was produced by an automated workflow._';
        $lines[] = '';

        $signal = $experiment->signals->first();
        if ($signal) {
            $lines[] = '### Triggering signal';
            $lines[] = '';
            $title = $signal->title ?? $signal->payload['title'] ?? 'unnamed signal';
            $lines[] = "- **Title:** {$title}";
            $lines[] = "- **Source:** {$signal->source}";
            $lines[] = "- **Signal ID:** `{$signal->id}`";
            if (! empty($signal->metadata['code_owners'])) {
                $owners = implode(', ', (array) $signal->metadata['code_owners']);
                $lines[] = "- **Code owners:** {$owners}";
            }
            $lines[] = '';
        }

        $steps = $experiment->playbookSteps->sortBy('order');
        if ($steps->isNotEmpty()) {
            $lines[] = '### Pipeline steps';
            $lines[] = '';
            $lines[] = '| # | Agent | Status | Cost | Duration |';
            $lines[] = '|---|-------|--------|------|----------|';

            foreach ($steps as $step) {
                /** @var PlaybookStep $step */
                $agentName = $step->agent?->name ?? '—';
                $status = $step->status;
                $cost = $step->cost_credits !== null ? "{$step->cost_credits} cr" : '—';
                $duration = $step->duration_ms !== null
                    ? round($step->duration_ms / 1000, 1).'s'
                    : '—';

                $lines[] = "| {$step->order} | {$agentName} | {$status} | {$cost} | {$duration} |";
            }
            $lines[] = '';

            // Surface the last meaningful output (the patch / final result)
            $lastWithOutput = $steps->reverse()->first(fn (PlaybookStep $s) => ! empty($s->output));
            if ($lastWithOutput) {
                $lines[] = '### Final step output';
                $lines[] = '';
                $lines[] = '```json';
                $lines[] = $this->compactJson($lastWithOutput->output);
                $lines[] = '```';
                $lines[] = '';
            }
        }

        $lines[] = '### Experiment';
        $lines[] = '';
        $lines[] = "- **ID:** `{$experiment->id}`";
        if ($experiment->title) {
            $lines[] = "- **Title:** {$experiment->title}";
        }
        $lines[] = "- **Status:** {$experiment->status->value}";
        if ($experiment->budget_spent_credits !== null) {
            $lines[] = "- **Total cost:** {$experiment->budget_spent_credits} credits";
        }

        return implode("\n", $lines);
    }

    /**
     * Render a provenance block from raw inputs — useful when called from
     * an agent before the experiment is finalised, or in tests.
     *
     * @param  array<string, mixed>  $context  Keys: signal_title, signal_source, steps (array of {agent, status, cost, duration_ms, output})
     */
    public function fromContext(array $context): string
    {
        $lines = [];
        $lines[] = '## Provenance';
        $lines[] = '';

        if (! empty($context['signal_title'])) {
            $lines[] = '### Triggering signal';
            $lines[] = '';
            $lines[] = "- **Title:** {$context['signal_title']}";
            if (! empty($context['signal_source'])) {
                $lines[] = "- **Source:** {$context['signal_source']}";
            }
            $lines[] = '';
        }

        if (! empty($context['steps']) && is_array($context['steps'])) {
            $lines[] = '### Pipeline steps';
            $lines[] = '';
            $lines[] = '| # | Agent | Status | Cost |';
            $lines[] = '|---|-------|--------|------|';

            foreach ($context['steps'] as $i => $step) {
                $agent = $step['agent'] ?? '—';
                $status = $step['status'] ?? '—';
                $cost = isset($step['cost']) ? "{$step['cost']} cr" : '—';
                $n = $i + 1;
                $lines[] = "| {$n} | {$agent} | {$status} | {$cost} |";
            }
            $lines[] = '';
        }

        return implode("\n", $lines);
    }

    /**
     * @param  array<string, mixed>  $data
     */
    private function compactJson(array $data): string
    {
        return json_encode(
            $data,
            JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE,
        ) ?: '{}';
    }
}
