// DBIS Volume XIV: Superposition-Based Asset Valuation (SBAV)
// Prices assets whose value exists in multiple simultaneous states

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';


export interface CreateSuperpositionAssetRequest {
  assetType: 'quantum_commodity' | 'parallel_sovereign_bond' | 'infinite_state_reserve';
  assetName: string;
  superpositionStates: Array<{
    stateIndex: number;
    stateValue: number;
    probability: number;
    stateMetadata?: Record<string, unknown>;
  }>;
}

export interface CollapseRequest {
  assetId: string;
  collapseStrategy?: 'most_consistent' | 'highest_probability' | 'weighted_average';
}

export class SbavService {
  /**
   * Create superposition asset
   */
  async createSuperpositionAsset(
    request: CreateSuperpositionAssetRequest
  ): Promise<{
    assetId: string;
    superposedValue: number;
    states: number;
  }> {
    const assetId = `SBAV-${uuidv4()}`;

    // Validate probabilities sum to 1
    const totalProbability = request.superpositionStates.reduce(
      (sum, state) => sum + state.probability,
      0
    );

    if (Math.abs(totalProbability - 1.0) > 0.01) {
      throw new Error(
        `Probabilities must sum to 1.0, got ${totalProbability}`
      );
    }

    // Calculate superposed value: value_superposed = Σ(state_value[i] * probability[i])
    const superposedValue = request.superpositionStates.reduce(
      (sum, state) => sum + state.stateValue * state.probability,
      0
    );

    // Create asset record
    const asset = await prisma.superpositionAsset.create({
      data: {
        assetId,
        assetType: request.assetType,
        assetName: request.assetName,
        superpositionStates: request.superpositionStates as unknown as object,
        stateProbabilities: request.superpositionStates.map(
          (s) => s.probability
        ) as unknown as object,
        superposedValue: new Decimal(superposedValue),
        collapseStatus: 'superposed',
      },
    });

    // Create valuation records for each state
    for (const state of request.superpositionStates) {
      await prisma.assetValuation.create({
        data: {
          valuationId: `VAL-${uuidv4()}`,
          assetId: asset.id,
          stateIndex: state.stateIndex,
          stateValue: new Decimal(state.stateValue),
          probability: new Decimal(state.probability),
          weightedValue: new Decimal(
            state.stateValue * state.probability
          ),
        },
      });
    }

    return {
      assetId: asset.assetId,
      superposedValue,
      states: request.superpositionStates.length,
    };
  }

  /**
   * Calculate superposed value: value_superposed = Σ(state_value[i] * probability[i])
   */
  async calculateSuperposedValue(assetId: string): Promise<{
    superposedValue: number;
    stateBreakdown: Array<{
      stateIndex: number;
      stateValue: number;
      probability: number;
      weightedValue: number;
    }>;
  }> {
    const asset = await prisma.superpositionAsset.findUnique({
      where: { assetId },
      include: {
        valuations: true,
      },
    });

    if (!asset) {
      throw new Error(`Asset ${assetId} not found`);
    }

    // Calculate from valuations
    const stateBreakdown = asset.valuations.map((v) => ({
      stateIndex: v.stateIndex || 0,
      stateValue: v.stateValue.toNumber(),
      probability: v.probability.toNumber(),
      weightedValue: v.weightedValue.toNumber(),
    }));

    const superposedValue = stateBreakdown.reduce(
      (sum, state) => sum + state.weightedValue,
      0
    );

    // Update asset with calculated value
    await prisma.superpositionAsset.update({
      where: { assetId },
      data: {
        superposedValue: new Decimal(superposedValue),
      },
    });

    return {
      superposedValue,
      stateBreakdown,
    };
  }

  /**
   * Collapse asset to single state: collapsed_value = select(most_consistent_state)
   */
  async collapseAsset(
    request: CollapseRequest
  ): Promise<{
    collapsed: boolean;
    collapsedValue: number;
    selectedState: number;
  }> {
    const asset = await prisma.superpositionAsset.findUnique({
      where: { assetId: request.assetId },
      include: {
        valuations: true,
      },
    });

    if (!asset) {
      throw new Error(`Asset ${request.assetId} not found`);
    }

    if (asset.collapseStatus === 'collapsed') {
      return {
        collapsed: true,
        collapsedValue: asset.collapsedValue?.toNumber() || 0,
        selectedState: 0,
      };
    }

    // Select state based on strategy
    const selectedState = this.selectState(
      asset.valuations,
      request.collapseStrategy || 'most_consistent'
    );

    const collapsedValue = selectedState.stateValue.toNumber();

    // Update asset
    await prisma.superpositionAsset.update({
      where: { assetId: request.assetId },
      data: {
        collapsedValue: selectedState.stateValue,
        collapseStatus: 'collapsed',
        collapsedAt: new Date(),
      },
    });

    // Perform reconciliation across parallel branches, quantum states, holographic projections
    await this.reconcileAfterCollapse(asset.id, selectedState);

    return {
      collapsed: true,
      collapsedValue,
      selectedState: selectedState.stateIndex || 0,
    };
  }

  /**
   * Select state based on collapse strategy
   */
  private selectState(
    valuations: Array<{
      stateIndex: number | null;
      stateValue: Decimal;
      probability: Decimal;
      weightedValue: Decimal;
    }>,
    strategy: 'most_consistent' | 'highest_probability' | 'weighted_average'
  ): {
    stateIndex: number | null;
    stateValue: Decimal;
    probability: Decimal;
    weightedValue: Decimal;
  } {
    if (valuations.length === 0) {
      throw new Error('No valuations available');
    }

    switch (strategy) {
      case 'highest_probability':
        // Select state with highest probability
        return valuations.reduce((max, v) =>
          v.probability.gt(max.probability) ? v : max
        );

      case 'weighted_average':
        // Use weighted average (already calculated in superposedValue)
        const totalWeighted = valuations.reduce(
          (sum, v) => sum + v.weightedValue.toNumber(),
          0
        );
        // Return state closest to weighted average
        return valuations.reduce((closest, v) => {
          const currentDiff = Math.abs(
            v.stateValue.toNumber() - totalWeighted
          );
          const closestDiff = Math.abs(
            closest.stateValue.toNumber() - totalWeighted
          );
          return currentDiff < closestDiff ? v : closest;
        });

      case 'most_consistent':
      default:
        // Select most consistent state (highest probability * value stability)
        return valuations.reduce((most, v) => {
          const currentScore =
            v.probability.toNumber() * v.stateValue.toNumber();
          const mostScore =
            most.probability.toNumber() * most.stateValue.toNumber();
          return currentScore > mostScore ? v : most;
        });
    }
  }

  /**
   * Reconcile after collapse across parallel branches, quantum states, holographic projections
   */
  private async reconcileAfterCollapse(
    assetDbId: string,
    selectedState: {
      stateIndex: number | null;
      stateValue: Decimal;
    }
  ): Promise<void> {
    // Create reconciliation records for different reconciliation types
    const reconciliationTypes = [
      'parallel_branch',
      'quantum_state',
      'holographic_projection',
    ];

    for (const reconciliationType of reconciliationTypes) {
      await prisma.assetReconciliation.create({
        data: {
          reconciliationId: `RECON-${uuidv4()}`,
          assetId: assetDbId,
          reconciliationType,
          beforeState: {
            status: 'superposed',
            note: 'Multiple simultaneous states',
          } as unknown as object,
          afterState: {
            status: 'collapsed',
            selectedStateIndex: selectedState.stateIndex,
            collapsedValue: selectedState.stateValue.toNumber(),
          } as unknown as object,
          reconciliationDetails: {
            reconciliationType,
            reconciledAt: new Date().toISOString(),
          } as unknown as object,
          status: 'reconciled',
          reconciledAt: new Date(),
        },
      });
    }
  }

  /**
   * Get superposition asset
   */
  async getSuperpositionAsset(assetId: string) {
    return prisma.superpositionAsset.findUnique({
      where: { assetId },
      include: {
        valuations: {
          orderBy: {
            stateIndex: 'asc',
          },
        },
        reconciliations: {
          orderBy: {
            createdAt: 'desc',
          },
          take: 10,
        },
      },
    });
  }

  /**
   * Update asset state probabilities
   */
  async updateStateProbabilities(
    assetId: string,
    stateProbabilities: Record<number, number>
  ): Promise<{
    updated: boolean;
    newSuperposedValue: number;
  }> {
    const asset = await prisma.superpositionAsset.findUnique({
      where: { assetId },
      include: {
        valuations: true,
      },
    });

    if (!asset) {
      throw new Error(`Asset ${assetId} not found`);
    }

    // Validate probabilities sum to 1
    const totalProbability = Object.values(stateProbabilities).reduce(
      (sum, p) => sum + p,
      0
    );

    if (Math.abs(totalProbability - 1.0) > 0.01) {
      throw new Error(
        `Probabilities must sum to 1.0, got ${totalProbability}`
      );
    }

    // Update valuations with new probabilities
    let newSuperposedValue = 0;
    for (const valuation of asset.valuations) {
      const stateIndex = valuation.stateIndex || 0;
      const newProbability = stateProbabilities[stateIndex];

      if (newProbability !== undefined) {
        const weightedValue =
          valuation.stateValue.toNumber() * newProbability;

        await prisma.assetValuation.update({
          where: { id: valuation.id },
          data: {
            probability: new Decimal(newProbability),
            weightedValue: new Decimal(weightedValue),
          },
        });

        newSuperposedValue += weightedValue;
      }
    }

    // Update asset
    await prisma.superpositionAsset.update({
      where: { assetId },
      data: {
        superposedValue: new Decimal(newSuperposedValue),
        stateProbabilities: stateProbabilities as unknown as object,
      },
    });

    return {
      updated: true,
      newSuperposedValue,
    };
  }

  /**
   * Add new state to superposition
   */
  async addSuperpositionState(
    assetId: string,
    state: {
      stateIndex: number;
      stateValue: number;
      probability: number;
      stateMetadata?: Record<string, unknown>;
    }
  ): Promise<{
    added: boolean;
    updatedSuperposedValue: number;
  }> {
    const asset = await prisma.superpositionAsset.findUnique({
      where: { assetId },
      include: {
        valuations: true,
      },
    });

    if (!asset) {
      throw new Error(`Asset ${assetId} not found`);
    }

    // Check if state index already exists
    const existingState = asset.valuations.find(
      (v) => v.stateIndex === state.stateIndex
    );

    if (existingState) {
      throw new Error(
        `State ${state.stateIndex} already exists for asset ${assetId}`
      );
    }

    // Create new valuation
    const weightedValue = state.stateValue * state.probability;
    await prisma.assetValuation.create({
      data: {
        valuationId: `VAL-${uuidv4()}`,
        assetId: asset.id,
        stateIndex: state.stateIndex,
        stateValue: new Decimal(state.stateValue),
        probability: new Decimal(state.probability),
        weightedValue: new Decimal(weightedValue),
      },
    });

    // Recalculate superposed value
    const result = await this.calculateSuperposedValue(assetId);

    // Update superposition states
    const currentStates = asset.superpositionStates as Array<{
      stateIndex: number;
      stateValue: number;
      probability: number;
    }>;
    const updatedStates = [
      ...currentStates,
      {
        stateIndex: state.stateIndex,
        stateValue: state.stateValue,
        probability: state.probability,
      },
    ];

    await prisma.superpositionAsset.update({
      where: { assetId },
      data: {
        superpositionStates: updatedStates as unknown as object,
      },
    });

    return {
      added: true,
      updatedSuperposedValue: result.superposedValue,
    };
  }
}

export const sbavService = new SbavService();

