// Compute Distribution Service
// Task distribution: compute_cost + latency + sovereign_priority + risk_weight

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';
import { dscmNodeManagerService } from './dscm-node-manager.service';


export interface ComputeTaskRequest {
  taskType: string;
  taskPayload: Record<string, unknown>;
  preferredNodeType?: string;
  sovereignBankId?: string;
}

export class ComputeDistributionService {
  /**
   * Distribute compute task
   */
  async distributeTask(request: ComputeTaskRequest) {
    // Get available nodes
    let nodes;
    if (request.preferredNodeType) {
      nodes = await dscmNodeManagerService.getNodesByType(request.preferredNodeType);
    } else {
      nodes = await prisma.dscm_nodes.findMany({
        where: {
          status: 'active',
        },
      });
    }

    if (nodes.length === 0) {
      throw new Error('No available compute nodes');
    }

    // Calculate distribution score for each node
    const nodeScores = await Promise.all(
      nodes.map(async (node) => {
        const computeCost = node.computeCapacity ? parseFloat(node.computeCapacity.toString()) : 0;
        const latency = node.latency || 0;
        const sovereignPriority = node.sovereignPriority || 0;
        const riskWeight = node.riskWeight ? parseFloat(node.riskWeight.toString()) : 0;

        // Distribution score calculation
        // Lower is better, so we use inverse for cost and risk
        const distributionScore = 
          (1 / (computeCost + 1)) + // Inverse cost
          (latency / 1000) + // Normalize latency
          (sovereignPriority / 10) + // Priority boost
          riskWeight; // Risk penalty

        return {
          nodeId: node.nodeId,
          nodeType: node.nodeType,
          distributionScore,
          computeCost,
          latency,
          sovereignPriority,
          riskWeight,
        };
      })
    );

    // Select node with best (lowest) distribution score
    const selectedNode = nodeScores.reduce((best, current) =>
      current.distributionScore < best.distributionScore ? current : best
    );

    // Create compute task
    const taskId = `TASK-${uuidv4()}`;

    const task = await prisma.compute_tasks.create({
      data: {
        taskId,
        nodeId: selectedNode.nodeId,
        taskType: request.taskType,
        taskPayload: request.taskPayload,
        computeCost: new Decimal(selectedNode.computeCost),
        latency: selectedNode.latency,
        distributionScore: new Decimal(selectedNode.distributionScore),
        status: 'pending',
        assignedAt: new Date(),
      },
    });

    return task;
  }

  /**
   * Start task execution
   */
  async startTask(taskId: string) {
    return await prisma.compute_tasks.update({
      where: { taskId },
      data: {
        status: 'executing',
        startedAt: new Date(),
      },
    });
  }

  /**
   * Complete task
   */
  async completeTask(taskId: string, result: Record<string, unknown>) {
    return await prisma.compute_tasks.update({
      where: { taskId },
      data: {
        status: 'completed',
        completedAt: new Date(),
        result,
      },
    });
  }

  /**
   * Get task by ID
   */
  async getTask(taskId: string) {
    return await prisma.compute_tasks.findUnique({
      where: { taskId },
      include: {
        node: true,
      },
    });
  }

  /**
   * Get tasks for node
   */
  async getTasksForNode(nodeId: string, status?: string) {
    const where: any = { nodeId };
    if (status) {
      where.status = status;
    }

    return await prisma.compute_tasks.findMany({
      where,
      orderBy: {
        assignedAt: 'desc',
      },
    });
  }
}

export const computeDistributionService = new ComputeDistributionService();

