<?php

namespace Mtc\Plugins\BlockManager\Services;

use Mtc\Modules\BlockRegistry\Models\BlockRegistry;
use Mtc\Modules\BlockRegistry\Models\EntityBlock;
use Mtc\Plugins\BlockManager\Models\BlockManagerBlock;

/**
 * Compares a draft's would-ship plan against the live BlockRegistry state and
 * counts EntityBlock placements at risk from removed/renamed fields. Pure read
 * service — no writes, no side effects.
 */
class BlockShipDiffService
{
    public function __construct(private TwigGenerator $generator)
    {
    }

    /**
     * @return array{
     *   shipped: bool,
     *   fields_diff: array{added: array, removed: array, renamed: array, unchanged: array},
     *   entity_block_usage: int,
     * }
     */
    public function diff(BlockManagerBlock $block): array
    {
        $wouldShip = $this->generator->deriveFields($block);
        $wouldShipNames = array_column($wouldShip, 'name');
        $wouldShipSet = array_flip($wouldShipNames);

        $registered = BlockRegistry::where('slug', $block->slug)->with('fields')->first();
        $existingFields = [];
        $existingByName = [];
        if ($registered) {
            foreach ($registered->fields as $f) {
                $entry = ['name' => $f->name, 'type' => $f->type];
                $existingFields[] = $entry;
                $existingByName[$f->name] = $entry;
            }
        }

        // Renames declared in the Fields panel — only count as renames when the
        // `from` name actually exists in the live BlockRegistry row (otherwise
        // the rename is a no-op against the live state).
        $renames = $this->renamesFromPanel($block);
        $renamed = [];
        foreach ($renames as $from => $to) {
            $from = (string) $from;
            $to = (string) $to;
            if ($from === '' || $to === '' || $from === $to) {
                continue;
            }
            if (isset($existingByName[$from])) {
                $renamed[] = ['from' => $from, 'to' => $to];
            }
        }
        $renamedFroms = array_column($renamed, 'from');
        $renamedTos = array_column($renamed, 'to');
        $renamedFromsSet = array_flip($renamedFroms);
        $renamedTosSet = array_flip($renamedTos);

        $added = [];
        $unchanged = [];
        foreach ($wouldShip as $f) {
            if (isset($renamedTosSet[$f['name']])) {
                continue;
            }
            $entry = ['name' => $f['name'], 'type' => $f['type']];
            if (isset($existingByName[$f['name']])) {
                $unchanged[] = $entry;
            } else {
                $added[] = $entry;
            }
        }

        $removed = [];
        foreach ($existingFields as $f) {
            if (isset($renamedFromsSet[$f['name']])) {
                continue;
            }
            if (!isset($wouldShipSet[$f['name']])) {
                $removed[] = $f;
            }
        }

        $usage = 0;
        if ($registered) {
            $atRisk = array_merge(array_column($removed, 'name'), $renamedFroms);
            if ($atRisk !== []) {
                $atRiskSet = array_flip($atRisk);
                foreach (EntityBlock::where('block_id', $registered->id)->select(['id', 'data'])->cursor() as $eb) {
                    $data = $eb->data;
                    if (!is_array($data)) {
                        continue;
                    }
                    if (array_intersect_key($data, $atRiskSet) !== []) {
                        $usage++;
                    }
                }
            }
        }

        return [
            'shipped'            => $block->last_shipped_at !== null,
            'fields_diff'        => [
                'added'     => $added,
                'removed'   => $removed,
                'renamed'   => $renamed,
                'unchanged' => $unchanged,
            ],
            'entity_block_usage' => $usage,
        ];
    }

    private function renamesFromPanel(BlockManagerBlock $block): array
    {
        $structure = $block->structure_json ?? [];
        if (!is_array($structure)) {
            return [];
        }
        $panel = $structure['fields_panel'] ?? [];
        if (!is_array($panel)) {
            return [];
        }
        $renames = $panel['renames'] ?? [];
        return is_array($renames) ? $renames : [];
    }
}
