// UDFO Ontology Validator Service

import prisma from '@/shared/database/prisma';
import {
  OntologyValidationRequest,
  OntologyValidationResult,
} from './types';
import { assetOntologyService } from './asset-ontology.service';
import { entityOntologyService } from './entity-ontology.service';
import { processOntologyService } from './process-ontology.service';
import { logger } from '@/infrastructure/monitoring/logger';


export class OntologyValidatorService {
  /**
   * Validate ontology definitions for smart contracts, CBDC ledgers, etc.
   */
  async validate(
    request: OntologyValidationRequest
  ): Promise<OntologyValidationResult> {
    const errors: string[] = [];
    const warnings: string[] = [];
    const suggestions: string[] = [];

    // Validate asset
    if (request.assetId) {
      const asset = await assetOntologyService.getAssetByCode(request.assetId);
      if (!asset) {
        errors.push(`Asset ${request.assetId} not found in ontology`);
      } else {
        // Validate asset properties
        if (!asset.properties || Object.keys(asset.properties).length === 0) {
          warnings.push(`Asset ${request.assetId} has no properties defined`);
        }
      }
    }

    // Validate entity
    if (request.entityId) {
      const entity = await entityOntologyService.getEntityByIdentifier(request.entityId);
      if (!entity) {
        errors.push(`Entity ${request.entityId} not found in ontology`);
      } else {
        // Validate entity properties
        if (!entity.properties || Object.keys(entity.properties).length === 0) {
          warnings.push(`Entity ${request.entityId} has no properties defined`);
        }
      }
    }

    // Validate process
    if (request.processId) {
      const process = await processOntologyService.getProcessByCode(request.processId);
      if (!process) {
        errors.push(`Process ${request.processId} not found in ontology`);
      } else {
        // Validate process inputs/outputs
        if (process.inputs.length === 0) {
          warnings.push(`Process ${request.processId} has no inputs defined`);
        }
        if (process.outputs.length === 0) {
          warnings.push(`Process ${request.processId} has no outputs defined`);
        }
      }
    }

    // Validate smart contract code
    if (request.contractCode) {
      const contractValidation = await this.validateContractCode(request.contractCode);
      errors.push(...contractValidation.errors);
      warnings.push(...contractValidation.warnings);
      suggestions.push(...contractValidation.suggestions);
    }

    const valid = errors.length === 0;

    logger.info(`Ontology validation completed`, {
      valid,
      errors: errors.length,
      warnings: warnings.length,
    });

    return {
      valid,
      errors,
      warnings,
      suggestions,
    };
  }

  /**
   * Validate smart contract code against ontology
   */
  private async validateContractCode(
    contractCode: string
  ): Promise<{ errors: string[]; warnings: string[]; suggestions: string[] }> {
    const errors: string[] = [];
    const warnings: string[] = [];
    const suggestions: string[] = [];

    // Check for ontology references
    const assetPattern = /Asset\((\w+)\)/g;
    const entityPattern = /Entity\((\w+)\)/g;
    const processPattern = /Process\((\w+)\)/g;

    const assetMatches = Array.from(contractCode.matchAll(assetPattern));
    const entityMatches = Array.from(contractCode.matchAll(entityPattern));
    const processMatches = Array.from(contractCode.matchAll(processPattern));

    // Validate asset references
    for (const match of assetMatches) {
      const assetCode = match[1];
      const asset = await assetOntologyService.getAssetByCode(assetCode);
      if (!asset) {
        errors.push(`Contract references unknown asset: ${assetCode}`);
      }
    }

    // Validate entity references
    for (const match of entityMatches) {
      const entityId = match[1];
      const entity = await entityOntologyService.getEntityByIdentifier(entityId);
      if (!entity) {
        errors.push(`Contract references unknown entity: ${entityId}`);
      }
    }

    // Validate process references
    for (const match of processMatches) {
      const processCode = match[1];
      const process = await processOntologyService.getProcessByCode(processCode);
      if (!process) {
        errors.push(`Contract references unknown process: ${processCode}`);
      }
    }

    // Suggest ontology usage if none found
    if (assetMatches.length === 0 && entityMatches.length === 0 && processMatches.length === 0) {
      suggestions.push('Consider using UDFO ontology definitions (Asset, Entity, Process) for better interoperability');
    }

    return { errors, warnings, suggestions };
  }

  /**
   * Get ontology mappings
   */
  async getMappings(
    sourceDomain: 'ASSET' | 'ENTITY' | 'PROCESS',
    sourceId: string
  ) {
    const mappings = await prisma.ontologyMapping.findMany({
      where: {
        sourceDomain,
        sourceId,
      },
    });

    return mappings;
  }
}

export const ontologyValidatorService = new OntologyValidatorService();

