<?php

declare(strict_types=1);

namespace App\Framework\Mcp\Tools;

use App\Framework\HttpClient\HttpClient;
use App\Framework\HttpClient\HttpMethod;
use App\Framework\Mcp\McpTool;

/**
 * Gitea Repository Management MCP Tools
 *
 * Provides AI-accessible Gitea API operations for repository management,
 * SSH key setup, and deployment automation.
 */
final readonly class GiteaTools
{
    public function __construct(
        private HttpClient $httpClient,
        private string $giteaUrl,
        private string $giteaUsername,
        private string $giteaPassword
    ) {
    }

    #[McpTool(
        name: 'gitea_create_repository',
        description: 'Create a new repository in Gitea'
    )]
    public function createRepository(
        string $name,
        string $description = '',
        bool $private = true,
        bool $autoInit = false,
        string $defaultBranch = 'main'
    ): array {
        $url = "{$this->giteaUrl}/api/v1/user/repos";

        $data = [
            'name' => $name,
            'description' => $description,
            'private' => $private,
            'auto_init' => $autoInit,
            'default_branch' => $defaultBranch,
        ];

        $result = $this->makeRequest(HttpMethod::POST, $url, $data);

        if ($result['success']) {
            return [
                'success' => true,
                'repository' => [
                    'name' => $result['response']['name'] ?? $name,
                    'full_name' => $result['response']['full_name'] ?? "{$this->giteaUsername}/$name",
                    'clone_url' => $result['response']['clone_url'] ?? null,
                    'ssh_url' => $result['response']['ssh_url'] ?? null,
                    'html_url' => $result['response']['html_url'] ?? null,
                    'private' => $result['response']['private'] ?? $private,
                    'id' => $result['response']['id'] ?? null,
                ],
            ];
        }

        return $result;
    }

    #[McpTool(
        name: 'gitea_list_repositories',
        description: 'List all repositories for the authenticated user'
    )]
    public function listRepositories(): array
    {
        $url = "{$this->giteaUrl}/api/v1/user/repos";

        $result = $this->makeRequest(HttpMethod::GET, $url);

        if ($result['success']) {
            $repos = array_map(function ($repo) {
                return [
                    'name' => $repo['name'] ?? 'unknown',
                    'full_name' => $repo['full_name'] ?? 'unknown',
                    'description' => $repo['description'] ?? '',
                    'private' => $repo['private'] ?? false,
                    'clone_url' => $repo['clone_url'] ?? null,
                    'ssh_url' => $repo['ssh_url'] ?? null,
                    'html_url' => $repo['html_url'] ?? null,
                ];
            }, $result['response'] ?? []);

            return [
                'success' => true,
                'repositories' => $repos,
                'count' => count($repos),
            ];
        }

        return $result;
    }

    #[McpTool(
        name: 'gitea_get_repository',
        description: 'Get details of a specific repository'
    )]
    public function getRepository(string $owner, string $repo): array
    {
        $url = "{$this->giteaUrl}/api/v1/repos/$owner/$repo";

        $result = $this->makeRequest(HttpMethod::GET, $url);

        if ($result['success']) {
            $repo = $result['response'];

            return [
                'success' => true,
                'repository' => [
                    'name' => $repo['name'] ?? 'unknown',
                    'full_name' => $repo['full_name'] ?? 'unknown',
                    'description' => $repo['description'] ?? '',
                    'private' => $repo['private'] ?? false,
                    'clone_url' => $repo['clone_url'] ?? null,
                    'ssh_url' => $repo['ssh_url'] ?? null,
                    'html_url' => $repo['html_url'] ?? null,
                    'default_branch' => $repo['default_branch'] ?? 'main',
                    'created_at' => $repo['created_at'] ?? null,
                    'updated_at' => $repo['updated_at'] ?? null,
                ],
            ];
        }

        return $result;
    }

    #[McpTool(
        name: 'gitea_delete_repository',
        description: 'Delete a repository'
    )]
    public function deleteRepository(string $owner, string $repo): array
    {
        $url = "{$this->giteaUrl}/api/v1/repos/$owner/$repo";

        return $this->makeRequest(HttpMethod::DELETE, $url);
    }

    #[McpTool(
        name: 'gitea_add_deploy_key',
        description: 'Add an SSH deploy key to a repository'
    )]
    public function addDeployKey(
        string $owner,
        string $repo,
        string $title,
        string $key,
        bool $readOnly = true
    ): array {
        $url = "{$this->giteaUrl}/api/v1/repos/$owner/$repo/keys";

        $data = [
            'title' => $title,
            'key' => $key,
            'read_only' => $readOnly,
        ];

        $result = $this->makeRequest(HttpMethod::POST, $url, $data);

        if ($result['success']) {
            return [
                'success' => true,
                'deploy_key' => [
                    'id' => $result['response']['id'] ?? null,
                    'title' => $result['response']['title'] ?? $title,
                    'key' => $result['response']['key'] ?? $key,
                    'read_only' => $result['response']['read_only'] ?? $readOnly,
                    'created_at' => $result['response']['created_at'] ?? null,
                ],
            ];
        }

        return $result;
    }

    #[McpTool(
        name: 'gitea_list_deploy_keys',
        description: 'List all deploy keys for a repository'
    )]
    public function listDeployKeys(string $owner, string $repo): array
    {
        $url = "{$this->giteaUrl}/api/v1/repos/$owner/$repo/keys";

        $result = $this->makeRequest(HttpMethod::GET, $url);

        if ($result['success']) {
            $keys = array_map(function ($key) {
                return [
                    'id' => $key['id'] ?? null,
                    'title' => $key['title'] ?? 'unknown',
                    'key' => $key['key'] ?? '',
                    'read_only' => $key['read_only'] ?? true,
                    'created_at' => $key['created_at'] ?? null,
                ];
            }, $result['response'] ?? []);

            return [
                'success' => true,
                'deploy_keys' => $keys,
                'count' => count($keys),
            ];
        }

        return $result;
    }

    #[McpTool(
        name: 'gitea_delete_deploy_key',
        description: 'Delete a deploy key from a repository'
    )]
    public function deleteDeployKey(string $owner, string $repo, int $keyId): array
    {
        $url = "{$this->giteaUrl}/api/v1/repos/$owner/$repo/keys/$keyId";

        return $this->makeRequest(HttpMethod::DELETE, $url);
    }

    #[McpTool(
        name: 'gitea_add_user_ssh_key',
        description: 'Add an SSH key to the authenticated user'
    )]
    public function addUserSshKey(string $title, string $key, bool $readOnly = false): array
    {
        $url = "{$this->giteaUrl}/api/v1/user/keys";

        $data = [
            'title' => $title,
            'key' => $key,
            'read_only' => $readOnly,
        ];

        $result = $this->makeRequest(HttpMethod::POST, $url, $data);

        if ($result['success']) {
            return [
                'success' => true,
                'ssh_key' => [
                    'id' => $result['response']['id'] ?? null,
                    'title' => $result['response']['title'] ?? $title,
                    'key' => $result['response']['key'] ?? $key,
                    'read_only' => $result['response']['read_only'] ?? $readOnly,
                    'created_at' => $result['response']['created_at'] ?? null,
                ],
            ];
        }

        return $result;
    }

    #[McpTool(
        name: 'gitea_list_user_ssh_keys',
        description: 'List all SSH keys for the authenticated user'
    )]
    public function listUserSshKeys(): array
    {
        $url = "{$this->giteaUrl}/api/v1/user/keys";

        $result = $this->makeRequest(HttpMethod::GET, $url);

        if ($result['success']) {
            $keys = array_map(function ($key) {
                return [
                    'id' => $key['id'] ?? null,
                    'title' => $key['title'] ?? 'unknown',
                    'key' => $key['key'] ?? '',
                    'fingerprint' => $key['fingerprint'] ?? '',
                    'read_only' => $key['read_only'] ?? false,
                    'created_at' => $key['created_at'] ?? null,
                ];
            }, $result['response'] ?? []);

            return [
                'success' => true,
                'ssh_keys' => $keys,
                'count' => count($keys),
            ];
        }

        return $result;
    }

    #[McpTool(
        name: 'gitea_delete_user_ssh_key',
        description: 'Delete an SSH key from the authenticated user'
    )]
    public function deleteUserSshKey(int $keyId): array
    {
        $url = "{$this->giteaUrl}/api/v1/user/keys/$keyId";

        return $this->makeRequest(HttpMethod::DELETE, $url);
    }

    #[McpTool(
        name: 'gitea_add_remote',
        description: 'Add Gitea repository as git remote'
    )]
    public function addRemote(
        string $remoteName,
        string $owner,
        string $repo,
        bool $useSsh = true
    ): array {
        // Get repository info first
        $repoInfo = $this->getRepository($owner, $repo);

        if (! $repoInfo['success']) {
            return $repoInfo;
        }

        $url = $useSsh
            ? $repoInfo['repository']['ssh_url']
            : $repoInfo['repository']['clone_url'];

        if (! $url) {
            return [
                'success' => false,
                'error' => 'Repository URL not found',
            ];
        }

        // Add remote via git command
        $output = [];
        $exitCode = 0;
        $command = sprintf(
            'git remote add %s %s 2>&1',
            escapeshellarg($remoteName),
            escapeshellarg($url)
        );
        exec($command, $output, $exitCode);

        if ($exitCode !== 0) {
            // Check if remote already exists
            if (str_contains(implode("\n", $output), 'already exists')) {
                return [
                    'success' => false,
                    'error' => 'Remote already exists',
                    'suggestion' => "Use 'git remote set-url $remoteName $url' to update",
                ];
            }

            return [
                'success' => false,
                'error' => 'Failed to add remote',
                'output' => implode("\n", $output),
                'exit_code' => $exitCode,
            ];
        }

        return [
            'success' => true,
            'remote_name' => $remoteName,
            'url' => $url,
            'use_ssh' => $useSsh,
        ];
    }

    #[McpTool(
        name: 'gitea_webhook_create',
        description: 'Create a webhook for a repository'
    )]
    public function createWebhook(
        string $owner,
        string $repo,
        string $url,
        string $contentType = 'json',
        array $events = ['push'],
        bool $active = true,
        ?string $secret = null
    ): array {
        $hookUrl = "{$this->giteaUrl}/api/v1/repos/$owner/$repo/hooks";

        $data = [
            'type' => 'gitea',
            'config' => [
                'url' => $url,
                'content_type' => $contentType,
                'secret' => $secret ?? '',
            ],
            'events' => $events,
            'active' => $active,
        ];

        $result = $this->makeRequest(HttpMethod::POST, $hookUrl, $data);

        if ($result['success']) {
            return [
                'success' => true,
                'webhook' => [
                    'id' => $result['response']['id'] ?? null,
                    'url' => $result['response']['config']['url'] ?? $url,
                    'events' => $result['response']['events'] ?? $events,
                    'active' => $result['response']['active'] ?? $active,
                    'created_at' => $result['response']['created_at'] ?? null,
                ],
            ];
        }

        return $result;
    }

    // ==================== Private Helper Methods ====================

    private function makeRequest(HttpMethod $method, string $url, ?array $data = null): array
    {
        try {
            $options = [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/json',
                    'Authorization' => 'Basic ' . base64_encode("{$this->giteaUsername}:{$this->giteaPassword}"),
                ],
                'verify_ssl' => false, // For self-signed certificates
            ];

            if ($data !== null) {
                $options['json'] = $data;
            }

            $response = $this->httpClient->request($method, $url, $options);

            $statusCode = $response->getStatusCode();
            $body = $response->getBody();

            // Decode JSON response
            $decoded = json_decode($body, true);

            if ($statusCode >= 200 && $statusCode < 300) {
                return [
                    'success' => true,
                    'response' => $decoded,
                    'http_code' => $statusCode,
                ];
            }

            return [
                'success' => false,
                'error' => $decoded['message'] ?? 'HTTP error ' . $statusCode,
                'response' => $decoded,
                'http_code' => $statusCode,
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => 'Request failed: ' . $e->getMessage(),
                'exception' => get_class($e),
            ];
        }
    }
}
