<?php

namespace App\Mcp\Tools\Agent;

use App\Domain\Agent\Actions\CreateAgentAction;
use App\Domain\Knowledge\Models\KnowledgeBase;
use App\Domain\Shared\Models\Team;
use App\Infrastructure\AI\Services\ProviderResolver;
use App\Mcp\Attributes\AssistantTool;
use App\Mcp\Concerns\HasStructuredErrors;
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Laravel\Mcp\Request;
use Laravel\Mcp\Response;
use Laravel\Mcp\Server\Tool;
use Laravel\Mcp\Server\Tools\Annotations\IsDestructive;

#[IsDestructive]
#[AssistantTool('write')]
class AgentCreateTool extends Tool
{
    use HasStructuredErrors;

    protected string $name = 'agent_create';

    protected string $description = 'Create a new AI agent. Specify name, role, goal, backstory, and optionally provider/model.';

    public function schema(JsonSchema $schema): array
    {
        return [
            'name' => $schema->string()
                ->description('Agent name')
                ->required(),
            'role' => $schema->string()
                ->description('Agent role description'),
            'goal' => $schema->string()
                ->description('Agent goal'),
            'backstory' => $schema->string()
                ->description('Agent backstory'),
            'taste' => $schema->string()
                ->description('Agent taste — aesthetic/judgment preferences: how it chooses among acceptable options, tone, what "good" looks like.'),
            'provider' => $schema->string()
                ->description('LLM provider key (e.g. anthropic, openai, google, claude-code). Defaults to platform default.'),
            'model' => $schema->string()
                ->description('LLM model name. Defaults to platform default.'),
            'personality' => $schema->object()
                ->description('Agent personality traits: {tone, communication_style, traits[], behavioral_rules[], response_format_preference}'),
            'data_classification' => $schema->string()
                ->description('Data classification level: public, internal, confidential, restricted. Confidential and restricted agents are routed to local-only providers.')
                ->enum(['public', 'internal', 'confidential', 'restricted']),
            'tool_profile' => $schema->string()
                ->description('Tool profile restricting tool access. Options: researcher, executor, communicator, analyst, admin, minimal'),
            'environment' => $schema->string()
                ->description('Environment preset that auto-attaches a tool bundle. Options: minimal, coding, browsing, restricted.')
                ->enum(['minimal', 'coding', 'browsing', 'restricted']),
            'reasoning_effort' => $schema->string()
                ->description('Extended thinking effort (Anthropic). Options: none, low, medium, high, auto. "auto" lets the platform pick by task complexity.')
                ->enum(['none', 'low', 'medium', 'high', 'auto']),
            'use_tool_search' => $schema->boolean()
                ->description('Enable semantic tool auto-discovery — at run time, up to tool_search_top_k matching tools from the team pool are auto-attached based on the user prompt.'),
            'tool_search_top_k' => $schema->integer()
                ->description('Maximum tools tool_search will surface per run (1–20, default 5). Only applies when use_tool_search=true.'),
            'sandbox_profile' => $schema->string()
                ->description('JSON string defining Docker sandbox profile for per-execution process isolation (enterprise only). Example: {"image":"python:3.12-alpine","memory":"512m","cpus":"1.0","network":"none","timeout":300}'),
            'knowledge_base_id' => $schema->string()
                ->description('UUID of a knowledge base to link to this agent for RAG-powered context'),
            'evaluation_enabled' => $schema->boolean()
                ->description('Enable A/B evaluation for this agent')
                ->default(false),
            'evaluation_sample_rate' => $schema->number()
                ->description('Fraction of requests to include in evaluation (0.0 to 1.0). Only used when evaluation_enabled is true.'),
            'heartbeat_definition' => $schema->object()
                ->description('Agent health check config: {enabled: bool, cron: string, prompt: string}'),
            'charter' => $schema->object()
                ->description('Charter-as-contract — the agent authority boundary: {owns: string[], refuses: string[], escalate_to: string, escalate_when: string[]}. Rendered into the system prompt when agent.charter.enabled is on.'),
        ];
    }

    public function handle(Request $request): Response
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'role' => 'nullable|string',
            'goal' => 'nullable|string',
            'backstory' => 'nullable|string',
            'taste' => 'nullable|string',
            'provider' => 'nullable|string|max:100',
            'model' => 'nullable|string|max:100',
            'personality' => 'nullable|array',
            'tool_profile' => 'nullable|string',
            'environment' => 'nullable|string|in:minimal,coding,browsing,restricted',
            'reasoning_effort' => 'nullable|string|in:none,low,medium,high,auto',
            'use_tool_search' => 'nullable|boolean',
            'tool_search_top_k' => 'nullable|integer|min:1|max:20',
            'data_classification' => 'nullable|string|in:public,internal,confidential,restricted',
            'sandbox_profile' => 'nullable|string',
            'knowledge_base_id' => 'nullable|uuid',
            'evaluation_enabled' => 'nullable|boolean',
            'evaluation_sample_rate' => 'nullable|numeric|min:0|max:1',
            'heartbeat_definition' => 'nullable|array',
            'charter' => 'nullable|array',
        ]);
        $teamId = (app()->bound('mcp.team_id') ? app('mcp.team_id') : null) ?? auth()->user()?->current_team_id;
        if (! $teamId) {
            return $this->permissionDeniedError('No current team.');
        }

        // IDOR guard: verify knowledge_base_id belongs to the team
        if (! empty($validated['knowledge_base_id'])) {
            $kbExists = KnowledgeBase::withoutGlobalScopes()
                ->where('id', $validated['knowledge_base_id'])
                ->where('team_id', $teamId)
                ->exists();
            if (! $kbExists) {
                return $this->notFoundError('knowledge base');
            }
        }

        // Parse optional sandbox_profile JSON string into an array
        $sandboxProfile = null;
        if (! empty($validated['sandbox_profile'])) {
            $sandboxProfile = json_decode($validated['sandbox_profile'], true);
            if (! is_array($sandboxProfile)) {
                return $this->invalidArgumentError('sandbox_profile must be a valid JSON object.');
            }
        }

        try {
            $team = Team::find($teamId);
            $resolved = app(ProviderResolver::class)->resolve(team: $team);

            $agent = app(CreateAgentAction::class)->execute(
                name: $validated['name'],
                provider: $validated['provider'] ?? $resolved['provider'],
                model: $validated['model'] ?? $resolved['model'],
                role: $validated['role'] ?? null,
                goal: $validated['goal'] ?? null,
                backstory: $validated['backstory'] ?? null,
                taste: $validated['taste'] ?? null,
                teamId: $teamId,
                personality: $validated['personality'] ?? null,
                dataClassification: $validated['data_classification'] ?? null,
            );

            if (! empty($validated['tool_profile'])) {
                $agent->update(['tool_profile' => $validated['tool_profile']]);
            }

            if (! empty($validated['environment'])) {
                $agent->update(['environment' => $validated['environment']]);
            }

            if (! empty($validated['charter'])) {
                $agent->update(['charter' => $validated['charter']]);
            }

            if (! empty($validated['reasoning_effort']) && $validated['reasoning_effort'] !== 'none') {
                $config = $agent->config ?? [];
                $config['reasoning_effort'] = $validated['reasoning_effort'];
                $agent->update(['config' => $config]);
            }

            if (! empty($validated['use_tool_search'])) {
                $config = $agent->fresh()->config ?? [];
                $config['use_tool_search'] = true;
                $config['tool_search_top_k'] = max(1, min(20, (int) ($validated['tool_search_top_k'] ?? 5)));
                $agent->update(['config' => $config]);
            }

            if ($sandboxProfile !== null) {
                $agent->update(['sandbox_profile' => $sandboxProfile]);
            }

            $extraFields = array_filter([
                'knowledge_base_id' => $validated['knowledge_base_id'] ?? null,
                'evaluation_enabled' => $validated['evaluation_enabled'] ?? null,
                'evaluation_sample_rate' => $validated['evaluation_sample_rate'] ?? null,
                'heartbeat_definition' => $validated['heartbeat_definition'] ?? null,
            ], fn ($v) => $v !== null);

            if (! empty($extraFields)) {
                $agent->update($extraFields);
            }

            return Response::text(json_encode([
                'success' => true,
                'agent_id' => $agent->id,
                'name' => $agent->name,
                'status' => $agent->status->value,
            ]));
        } catch (\Throwable $e) {
            throw $e;
        }
    }
}
