import type * as shxInterfaces from '@smarthome.exchange/interfaces';
import { SimpleLocalMapper, type IIntegrationEntity, type ISimpleLocalEntitySnapshot, type ISimpleLocalSnapshot, type ISimpleLocalSnapshotOptions, type TSimpleLocalRawData } from '../../core/index.js';
import type { IMcpServerConfig, IMcpServerRawState } from './mcp_server.types.js';
import { mcpServerProfile } from './mcp_server.types.js';

export class McpServerMapper {
  public static toSnapshot(optionsArg: Omit<ISimpleLocalSnapshotOptions<IMcpServerConfig>, 'profile'>): ISimpleLocalSnapshot {
    const rawState = mcpServerRawState(optionsArg.rawData) || mcpServerRawState(optionsArg.config.rawData);
    if (rawState) {
      return mcpServerSnapshot(optionsArg.config, rawState, optionsArg.online ?? rawState.initialized, optionsArg.source || 'http', optionsArg.error);
    }
    return SimpleLocalMapper.toSnapshot({ ...optionsArg, profile: mcpServerProfile });
  }

  public static toSnapshotFromRaw(configArg: IMcpServerConfig, rawDataArg: TSimpleLocalRawData): ISimpleLocalSnapshot {
    return this.toSnapshot({ config: configArg, rawData: rawDataArg, online: true, source: 'manual' });
  }

  public static toDevices(snapshotArg: ISimpleLocalSnapshot): shxInterfaces.data.IDeviceDefinition[] {
    return SimpleLocalMapper.toDevices(mcpServerProfile, snapshotArg);
  }

  public static toEntities(snapshotArg: ISimpleLocalSnapshot): IIntegrationEntity[] {
    return SimpleLocalMapper.toEntities(mcpServerProfile, snapshotArg);
  }

  public static slug(valueArg: unknown): string {
    return SimpleLocalMapper.slug(valueArg);
  }

  public static clone<TValue>(valueArg: TValue): TValue {
    return SimpleLocalMapper.clone(valueArg);
  }
}

const mcpServerSnapshot = (configArg: IMcpServerConfig, rawDataArg: IMcpServerRawState, onlineArg: boolean, sourceArg: ISimpleLocalSnapshot['source'], errorArg?: string): ISimpleLocalSnapshot => {
  const endpoint = rawDataArg.endpointUrl || configArg.url || endpointFromHost(configArg);
  const serverName = configArg.name || rawDataArg.serverInfo?.name || mcpServerProfile.defaultName || mcpServerProfile.displayName;
  return {
    device: {
      id: configArg.uniqueId || endpoint || rawDataArg.serverInfo?.name || mcpServerProfile.domain,
      name: serverName,
      manufacturer: 'Home Assistant',
      model: 'Home Assistant MCP Server',
      protocol: endpoint?.startsWith('https://') ? 'https' : 'http',
      configurationUrl: endpoint,
      attributes: cleanAttributes({ protocolVersion: rawDataArg.protocolVersion, serverVersion: rawDataArg.serverInfo?.version, ...configArg.metadata }),
    },
    entities: mcpServerEntities(rawDataArg, onlineArg),
    online: onlineArg,
    updatedAt: rawDataArg.fetchedAt || new Date().toISOString(),
    source: sourceArg,
    rawData: rawDataArg,
    error: errorArg,
    capabilities: {
      localRead: true,
      localControl: true,
      streamableHttp: true,
    },
  };
};

const mcpServerEntities = (rawDataArg: IMcpServerRawState, onlineArg: boolean): ISimpleLocalEntitySnapshot[] => {
  const entities: ISimpleLocalEntitySnapshot[] = [
    { id: 'initialized', name: 'Initialized', platform: 'binary_sensor', state: rawDataArg.initialized, available: onlineArg, writable: false },
    { id: 'tool_count', name: 'Tool Count', platform: 'sensor', state: rawDataArg.toolCount, available: onlineArg, writable: false },
    { id: 'prompt_count', name: 'Prompt Count', platform: 'sensor', state: rawDataArg.promptCount, available: onlineArg, writable: false },
    { id: 'resource_count', name: 'Resource Count', platform: 'sensor', state: rawDataArg.resourceCount, available: onlineArg, writable: false },
  ];

  for (const tool of rawDataArg.tools) {
    entities.push({
      id: `tool_${SimpleLocalMapper.slug(tool.name)}`,
      uniqueId: `mcp_server_tool_${SimpleLocalMapper.slug(tool.name)}`,
      name: `Tool ${tool.name}`,
      platform: 'sensor',
      state: 'available',
      available: onlineArg,
      writable: true,
      attributes: cleanAttributes({ description: tool.description, inputSchema: tool.inputSchema }),
    });
  }

  for (const resource of rawDataArg.resources) {
    entities.push({
      id: `resource_${SimpleLocalMapper.slug(resource.name || resource.uri)}`,
      name: `Resource ${resource.title || resource.name || resource.uri}`,
      platform: 'sensor',
      state: resource.uri,
      available: onlineArg,
      writable: false,
      attributes: cleanAttributes({ description: resource.description, mimeType: resource.mimeType }),
    });
  }

  return entities;
};

const mcpServerRawState = (valueArg: unknown): IMcpServerRawState | undefined => {
  if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)) {
    return undefined;
  }
  const value = valueArg as Partial<IMcpServerRawState>;
  if (Array.isArray(value.tools) && Array.isArray(value.prompts) && Array.isArray(value.resources) && typeof value.initialized === 'boolean') {
    return value as IMcpServerRawState;
  }
  return undefined;
};

const endpointFromHost = (configArg: IMcpServerConfig): string | undefined => {
  if (!configArg.host) {
    return undefined;
  }
  const protocol = configArg.useTls ? 'https' : 'http';
  const port = configArg.port ? `:${configArg.port}` : '';
  const path = configArg.path || mcpServerProfile.defaultHttpPath || '/api/mcp';
  return `${protocol}://${configArg.host}${port}${path.startsWith('/') ? path : `/${path}`}`;
};

const cleanAttributes = (attributesArg: Record<string, unknown>): Record<string, unknown> | undefined => {
  const clean = Object.fromEntries(Object.entries(attributesArg).filter(([, valueArg]) => valueArg !== undefined));
  return Object.keys(clean).length ? clean : undefined;
};
