/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */

import { Behavior } from "#behavior/Behavior.js";
import { RootSupervisor } from "#behavior/supervision/RootSupervisor.js";
import { InternalError } from "@matter/general";
import { ClusterModel, CommandModel } from "@matter/model";
import { StatusResponse } from "@matter/types";
import { ApiResource } from "../ApiResource.js";
import { CommandResource } from "./CommandResource.js";
import { PropertyResource } from "./PropertyResource.js";

/**
 * API item for behaviors.
 */
export class BehaviorResource extends PropertyResource {
    #behavior: Behavior;

    override get valueKind(): ApiResource.Kind {
        return "cluster";
    }

    constructor(behavior: Behavior, parent: ApiResource) {
        const { id, supervisor } = behavior.type;
        if (supervisor === undefined) {
            throw new InternalError(`API behavior reference has no value supervisor`);
        }

        super(parent, id, supervisor, behavior.endpoint.path.at(id));
        this.#behavior = behavior;
    }

    override get value() {
        return this.#behavior.state;
    }

    override write() {
        throw new StatusResponse.UnsupportedWriteError(`Only patch supported for this path`);
    }

    override async childFor(id: string) {
        // "state" is a view of the cluster without commands; adds consistency w/ JS API and useful for handling name
        // collision
        if (id === "state") {
            return new PropertyResource(this, "state", this.supervisor, this.dataModelPath.at("state"));
        }

        // For direct children, commands take precedence should there be a name collision
        if (this.schema instanceof ClusterModel) {
            const command = this.schema.conformant.commands.for(id, CommandModel);
            if (command) {
                return new CommandResource(this, this.#behavior, command);
            }
        }

        // Now attributes (or fields in case of non-Matter properties)
        return super.childFor(id);
    }

    override get rootSupervisor() {
        return this.supervisor as RootSupervisor;
    }
}
