import * as plugins from '../plugins.js';
import type { OpsServer } from './classes.opsserver.js';
import type { IDomain, IPlatformService, IService } from '../types.js';

export class McpManager {
  private handler: plugins.smartmcp.ISmartMcpHttpHandler;

  constructor(private opsServerRef: OpsServer) {
    this.handler = plugins.smartmcp.createSmartMcpHttpHandler({
      name: 'onebox-mcp',
      version: '1.0.0',
      validateRequest: ({ request }) => this.validateRequest(request),
      authorize: async ({ request }) => this.authorizeRequest(request),
      tools: [
        {
          name: 'onebox_list_services',
          description: 'List Onebox services without environment variables or secrets.',
          handler: async () => ({
            services: (await this.opsServerRef.oneboxRef.database.getAllServices()).map((serviceArg) =>
              this.summarizeService(serviceArg),
            ),
          }),
        },
        {
          name: 'onebox_get_service',
          description: 'Get one Onebox service summary by name without environment variables or secrets.',
          inputSchema: {
            name: plugins.smartmcp.z.string().describe('Service name'),
          },
          handler: async (args) => {
            const serviceName = String(args.name || '').trim();
            const service = serviceName
              ? await this.opsServerRef.oneboxRef.database.getServiceByName(serviceName)
              : null;
            return {
              service: service ? this.summarizeService(service) : null,
            };
          },
        },
        {
          name: 'onebox_list_domains',
          description: 'List Onebox domains without DNS provider credentials or certificate material.',
          handler: async () => ({
            domains: (await this.opsServerRef.oneboxRef.database.getAllDomains()).map((domainArg) =>
              this.summarizeDomain(domainArg),
            ),
          }),
        },
        {
          name: 'onebox_list_platform_services',
          description: 'List Onebox platform services without admin credentials or environment variables.',
          handler: async () => ({
            platformServices: (await this.opsServerRef.oneboxRef.database.getAllPlatformServices()).map((serviceArg) =>
              this.summarizePlatformService(serviceArg),
            ),
          }),
        },
      ],
    });
  }

  public async handleRequest(requestArg: Request): Promise<Response> {
    return this.handler.handleRequest(requestArg);
  }

  public getHandler(): plugins.smartmcp.ISmartMcpHttpHandler {
    return this.handler;
  }

  private validateRequest(requestArg: Request): Response | undefined {
    const origin = requestArg.headers.get('origin');
    if (origin && origin !== new URL(requestArg.url).origin) {
      return new Response('Forbidden', { status: 403 });
    }
  }

  private async authorizeRequest(requestArg: Request): Promise<Response | { token: string; clientId: string; scopes: string[] }> {
    const jwt = this.extractBearerToken(requestArg);
    if (!jwt) {
      return new Response('Unauthorized', { status: 401 });
    }

    try {
      const identity = await this.opsServerRef.adminHandler.getVerifiedAdminIdentity({
        jwt,
        userId: '',
        username: '',
        expiresAt: 0,
        role: 'user',
      });
      return {
        token: jwt,
        clientId: identity.userId || identity.username,
        scopes: ['admin', 'mcp', 'onebox:read'],
      };
    } catch {
      return new Response('Unauthorized', { status: 401 });
    }
  }

  private extractBearerToken(requestArg: Request): string | undefined {
    const authHeader = requestArg.headers.get('authorization');
    if (!authHeader) {
      return undefined;
    }
    const [scheme, token] = authHeader.split(' ');
    if (scheme?.toLowerCase() !== 'bearer' || !token) {
      return undefined;
    }
    return token.trim() || undefined;
  }

  private summarizeService(serviceArg: IService) {
    return {
      id: serviceArg.id,
      name: serviceArg.name,
      image: serviceArg.image,
      registry: serviceArg.registry,
      port: serviceArg.port,
      domain: serviceArg.domain,
      status: serviceArg.status,
      containerID: serviceArg.containerID,
      useOneboxRegistry: serviceArg.useOneboxRegistry,
      registryRepository: serviceArg.registryRepository,
      registryImageTag: serviceArg.registryImageTag,
      autoUpdateOnPush: serviceArg.autoUpdateOnPush,
      imageDigest: serviceArg.imageDigest,
      platformRequirements: serviceArg.platformRequirements,
      appTemplateId: serviceArg.appTemplateId,
      appTemplateVersion: serviceArg.appTemplateVersion,
      volumes: serviceArg.volumes?.map((volumeArg) => ({
        name: volumeArg.name,
        source: volumeArg.source,
        mountPath: volumeArg.mountPath,
        storageClass: volumeArg.storageClass,
        driver: volumeArg.driver,
        readOnly: volumeArg.readOnly,
        backup: volumeArg.backup,
      })),
      publishedPorts: serviceArg.publishedPorts,
      createdAt: serviceArg.createdAt,
      updatedAt: serviceArg.updatedAt,
    };
  }

  private summarizeDomain(domainArg: IDomain) {
    return {
      id: domainArg.id,
      domain: domainArg.domain,
      dnsProvider: domainArg.dnsProvider,
      isObsolete: domainArg.isObsolete,
      defaultWildcard: domainArg.defaultWildcard,
      createdAt: domainArg.createdAt,
      updatedAt: domainArg.updatedAt,
    };
  }

  private summarizePlatformService(serviceArg: IPlatformService) {
    return {
      id: serviceArg.id,
      name: serviceArg.name,
      type: serviceArg.type,
      status: serviceArg.status,
      containerId: serviceArg.containerId,
      config: {
        image: serviceArg.config?.image,
        port: serviceArg.config?.port,
        volumes: serviceArg.config?.volumes,
        storageClass: serviceArg.config?.storageClass,
        command: serviceArg.config?.command,
      },
      createdAt: serviceArg.createdAt,
      updatedAt: serviceArg.updatedAt,
    };
  }
}
