<?php

/**
 * LolaCore - Playbook value object
 *
 * Immutable representation of a parsed and validated Playbook. Built from
 * the frontmatter array produced by YamlParser + PlaybookValidator and
 * the raw markdown body.
 *
 * @package LolaCore
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\Playbooks;

class Playbook
{
    public const ORIGIN_BUILT_IN   = 'built_in';
    public const ORIGIN_ADDON      = 'addon';
    public const ORIGIN_FILESYSTEM = 'filesystem';
    public const ORIGIN_DB         = 'db';

    public const STATUS_ACTIVE   = 'active';
    public const STATUS_INACTIVE = 'inactive';
    public const STATUS_ARCHIVED = 'archived';

    public const TYPE_SYSTEM  = 'system';
    public const TYPE_PROJECT = 'project';

    private const DEFAULT_TRIGGERS = [
        'keywords' => [],
    ];

    private string $name;
    private string $description;
    private string $domain;
    private string $type;
    private string $body;
    private string $origin;
    /** @var array<int,string> */
    private array $abilityPrefixes;
    /** @var array{keywords: array<int,string>} */
    private array $triggers;
    private ?string $version;
    private string $minLolaVersion;
    private string $status;

    /**
     * @param array<int,string>                              $abilityPrefixes
     * @param array{keywords?: array<int,string>}            $triggers
     */
    public function __construct(
        string $name,
        string $description,
        string $domain,
        string $type,
        string $body,
        string $origin,
        array $abilityPrefixes = [],
        array $triggers = [],
        ?string $version = null,
        string $minLolaVersion = '',
        string $status = self::STATUS_ACTIVE
    ) {
        $this->name             = $name;
        $this->description      = $description;
        $this->domain           = $domain;
        $this->type             = $type;
        $this->body             = $body;
        $this->origin           = $origin;
        $this->abilityPrefixes  = $abilityPrefixes;
        $this->triggers         = array_merge(self::DEFAULT_TRIGGERS, $triggers);
        $this->version          = $version;
        $this->minLolaVersion   = $minLolaVersion;
        $this->status           = $status;
    }

    /**
     * @param array<string,mixed> $frontmatter Validated frontmatter array.
     * @param string              $body        Verbatim markdown body.
     * @param string              $origin      One of the ORIGIN_* constants.
     */
    public static function fromParsed(array $frontmatter, string $body, string $origin): self
    {
        $triggers = is_array($frontmatter['triggers'] ?? null)
            ? $frontmatter['triggers']
            : [];

        $abilityPrefixes = is_array($frontmatter['ability_prefixes'] ?? null)
            ? array_values(array_map('strval', $frontmatter['ability_prefixes']))
            : [];

        $defaultType = $origin === self::ORIGIN_DB ? self::TYPE_PROJECT : self::TYPE_SYSTEM;
        $type        = isset($frontmatter['type']) && is_string($frontmatter['type']) && $frontmatter['type'] !== ''
            ? (string) $frontmatter['type']
            : $defaultType;

        return new self(
            name: (string) ($frontmatter['name'] ?? ''),
            description: (string) ($frontmatter['description'] ?? ''),
            domain: (string) ($frontmatter['domain'] ?? ''),
            type: $type,
            body: $body,
            origin: $origin,
            abilityPrefixes: $abilityPrefixes,
            triggers: $triggers,
            version: isset($frontmatter['version']) && $frontmatter['version'] !== null
                ? (string) $frontmatter['version']
                : null,
            minLolaVersion: (string) ($frontmatter['min_lolacore_version'] ?? ''),
            status: (string) ($frontmatter['status'] ?? self::STATUS_ACTIVE),
        );
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getSlug(): string
    {
        return $this->name;
    }

    public function getDescription(): string
    {
        return $this->description;
    }

    public function getDomain(): string
    {
        return $this->domain;
    }

    public function getType(): string
    {
        return $this->type;
    }

    public function getBody(): string
    {
        return $this->body;
    }

    public function getOrigin(): string
    {
        return $this->origin;
    }

    /**
     * @return array<int,string>
     */
    public function getAbilityPrefixes(): array
    {
        return $this->abilityPrefixes;
    }

    /**
     * @return array{keywords: array<int,string>}
     */
    public function getTriggers(): array
    {
        return $this->triggers;
    }

    public function getVersion(): ?string
    {
        return $this->version;
    }

    public function getMinLolaVersion(): string
    {
        return $this->minLolaVersion;
    }

    public function getStatus(): string
    {
        return $this->status;
    }

    public function isActivatable(): bool
    {
        return $this->status === self::STATUS_ACTIVE;
    }

    public function withStatus(string $status): self
    {
        $clone         = clone $this;
        $clone->status = $status;
        return $clone;
    }

    /**
     * @return array<string,mixed>
     */
    public function toArray(): array
    {
        return [
            'name'                 => $this->name,
            'description'          => $this->description,
            'domain'               => $this->domain,
            'type'                 => $this->type,
            'body'                 => $this->body,
            'origin'               => $this->origin,
            'ability_prefixes'     => $this->abilityPrefixes,
            'triggers'             => $this->triggers,
            'version'              => $this->version,
            'min_lolacore_version' => $this->minLolaVersion,
            'status'               => $this->status,
        ];
    }

    /**
     * @param array<string,mixed> $data
     */
    public static function fromArray(array $data): self
    {
        $triggers = is_array($data['triggers'] ?? null) ? $data['triggers'] : [];
        $prefixes = is_array($data['ability_prefixes'] ?? null) ? $data['ability_prefixes'] : [];

        return new self(
            name: (string) ($data['name'] ?? ''),
            description: (string) ($data['description'] ?? ''),
            domain: (string) ($data['domain'] ?? ''),
            type: (string) ($data['type'] ?? self::TYPE_PROJECT),
            body: (string) ($data['body'] ?? ''),
            origin: (string) ($data['origin'] ?? self::ORIGIN_BUILT_IN),
            abilityPrefixes: array_values(array_map('strval', $prefixes)),
            triggers: $triggers,
            version: isset($data['version']) && $data['version'] !== null ? (string) $data['version'] : null,
            minLolaVersion: (string) ($data['min_lolacore_version'] ?? ''),
            status: (string) ($data['status'] ?? self::STATUS_ACTIVE),
        );
    }
}
