// STCE Projection Service
// Future/retro economic projections

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


export interface CreateProjectionRequest {
  tcuId: string;
  projectionType: 'forward_indexed' | 'retro_correction';
  timeDelta: string;
  projectedValue: string;
  economicData?: Record<string, unknown>;
  confidence?: string;
}

export interface ProjectionResult {
  projectionId: string;
  projectedValue: string;
  confidence?: string;
  projectedAt: Date;
}

export class StceProjectionService {
  /**
   * Create a temporal projection
   */
  async createProjection(
    request: CreateProjectionRequest
  ): Promise<TemporalProjection> {
    // Verify TCU exists
    const tcu = await prisma.temporal_currency_units.findUnique({
      where: { tcuId: request.tcuId },
    });

    if (!tcu) {
      throw new Error(`TCU not found: ${request.tcuId}`);
    }

    const projectionId = `TCU-PROJ-${uuidv4()}`;

    const projection = await prisma.temporal_projections.create({
      data: {
        projectionId,
        tcuId: request.tcuId,
        projectionType: request.projectionType,
        timeDelta: new Decimal(request.timeDelta),
        projectedValue: new Decimal(request.projectedValue),
        economicData: request.economicData || {},
        confidence: request.confidence ? new Decimal(request.confidence) : null,
        projectedAt: new Date(),
      },
    });

    return {
      projectionId: projection.projectionId,
      tcuId: projection.tcuId,
      projectionType: projection.projectionType as 'forward_indexed' | 'retro_correction',
      timeDelta: projection.timeDelta.toString(),
      projectedValue: projection.projectedValue.toString(),
      economicData: (projection.economicData as Record<string, unknown>) || undefined,
      confidence: projection.confidence?.toString(),
      projectedAt: projection.projectedAt,
    };
  }

  /**
   * Calculate forward-indexed value projection
   * future_weight = projection(t+Δt)
   */
  async calculateForwardProjection(
    tcuId: string,
    timeDelta: string
  ): Promise<ProjectionResult> {
    const tcu = await prisma.temporal_currency_units.findUnique({
      where: { tcuId },
    });

    if (!tcu) {
      throw new Error(`TCU not found: ${tcuId}`);
    }

    // Get recent projections for trend analysis
    const recentProjections = await prisma.temporal_projections.findMany({
      where: {
        tcuId,
        projectionType: 'forward_indexed',
      },
      orderBy: { projectedAt: 'desc' },
      take: 10,
    });

    // Simple projection model: use trend from recent projections
    // In production, this would use sophisticated economic models
    const baseValue = tcu.presentValue;
    const delta = new Decimal(timeDelta);

    // Calculate projected value (simplified model)
    // In reality, this would use complex economic projections
    const trendFactor = new Decimal(1.001); // 0.1% per time unit (example)
    const projectedValue = baseValue.mul(trendFactor.pow(delta));

    // Calculate confidence based on historical accuracy
    const confidence = recentProjections.length > 0 
      ? new Decimal(0.85) // 85% confidence if we have history
      : new Decimal(0.70); // 70% confidence for new projections

    const projection = await this.createProjection({
      tcuId,
      projectionType: 'forward_indexed',
      timeDelta,
      projectedValue: projectedValue.toString(),
      confidence: confidence.toString(),
      economicData: {
        baseValue: baseValue.toString(),
        timeDelta: timeDelta,
        trendFactor: trendFactor.toString(),
      },
    });

    return {
      projectionId: projection.projectionId,
      projectedValue: projection.projectedValue,
      confidence: projection.confidence,
      projectedAt: projection.projectedAt,
    };
  }

  /**
   * Calculate retro-correction factor
   * retro_factor = correction(t-Δt)
   */
  async calculateRetroCorrection(
    tcuId: string,
    timeDelta: string
  ): Promise<ProjectionResult> {
    const tcu = await prisma.temporal_currency_units.findUnique({
      where: { tcuId },
    });

    if (!tcu) {
      throw new Error(`TCU not found: ${tcuId}`);
    }

    // Get historical stability states for backward alignment
    const historicalStates = await prisma.temporal_stability_states.findMany({
      where: { tcuId },
      orderBy: { calculatedAt: 'desc' },
      take: 10,
    });

    // Calculate retro-correction based on past deviations
    // Simplified model: small correction factor if historical variance is low
    const baseValue = tcu.presentValue;
    const delta = new Decimal(timeDelta);

    // Calculate correction factor (typically small, can be negative)
    let correctionFactor = new Decimal(1.0);
    if (historicalStates.length > 0) {
      // Use average deviation from recent states
      const avgDeviation = historicalStates.reduce((sum, state) => {
        const deviation = state.calculatedValue.minus(state.presentValue);
        return sum.plus(deviation.abs());
      }, new Decimal(0)).div(historicalStates.length);

      // Correction factor inversely related to past deviations
      correctionFactor = new Decimal(1).minus(avgDeviation.div(baseValue).mul(0.1));
    }

    const retroValue = baseValue.mul(correctionFactor);
    const confidence = new Decimal(0.80); // Retro-corrections have lower confidence

    const projection = await this.createProjection({
      tcuId,
      projectionType: 'retro_correction',
      timeDelta,
      projectedValue: retroValue.toString(),
      confidence: confidence.toString(),
      economicData: {
        baseValue: baseValue.toString(),
        timeDelta: timeDelta,
        correctionFactor: correctionFactor.toString(),
      },
    });

    return {
      projectionId: projection.projectionId,
      projectedValue: projection.projectedValue,
      confidence: projection.confidence,
      projectedAt: projection.projectedAt,
    };
  }

  /**
   * Get projections for a TCU
   */
  async getProjectionsByTcu(tcuId: string): Promise<TemporalProjection[]> {
    const projections = await prisma.temporal_projections.findMany({
      where: { tcuId },
      orderBy: { projectedAt: 'desc' },
    });

    return projections.map((proj) => ({
      projectionId: proj.projectionId,
      tcuId: proj.tcuId,
      projectionType: proj.projectionType as 'forward_indexed' | 'retro_correction',
      timeDelta: proj.timeDelta.toString(),
      projectedValue: proj.projectedValue.toString(),
      economicData: (proj.economicData as Record<string, unknown>) || undefined,
      confidence: proj.confidence?.toString(),
      projectedAt: proj.projectedAt,
    }));
  }
}

