import 'dart:math' as math;
import '../../../domain/entities/kline.dart';

/// K线数据处理器 - 计算各种技术指标
class KlineDataProcessor {
  final List<Kline> klines;

  KlineDataProcessor(this.klines);

  /// 计算MA（简单移动平均线）
  /// periods: [5, 10, 20, 60] 等周期
  Map<int, List<double?>> calculateMA(List<int> periods) {
    final result = <int, List<double?>>{};

    for (final period in periods) {
      final maList = <double?>[];
      for (int i = 0; i < klines.length; i++) {
        if (i < period - 1) {
          maList.add(null);
        } else {
          double sum = 0;
          for (int j = i - period + 1; j <= i; j++) {
            sum += double.tryParse(klines[j].close) ?? 0;
          }
          maList.add(sum / period);
        }
      }
      result[period] = maList;
    }

    return result;
  }

  /// 计算EMA（指数移动平均线）
  Map<int, List<double?>> calculateEMA(List<int> periods) {
    final result = <int, List<double?>>{};

    for (final period in periods) {
      final emaList = <double?>[];
      final multiplier = 2.0 / (period + 1);
      double? prevEma;

      for (int i = 0; i < klines.length; i++) {
        final close = double.tryParse(klines[i].close) ?? 0;

        if (i < period - 1) {
          emaList.add(null);
        } else if (i == period - 1) {
          // 第一个EMA使用SMA
          double sum = 0;
          for (int j = 0; j <= i; j++) {
            sum += double.tryParse(klines[j].close) ?? 0;
          }
          prevEma = sum / period;
          emaList.add(prevEma);
        } else {
          // EMA = (Close - EMA(prev)) * multiplier + EMA(prev)
          prevEma = (close - prevEma!) * multiplier + prevEma;
          emaList.add(prevEma);
        }
      }
      result[period] = emaList;
    }

    return result;
  }

  /// 计算BOLL（布林带）
  /// 默认周期20，标准差倍数2
  Map<String, List<double?>> calculateBOLL({int period = 20, double stdDev = 2}) {
    final middle = <double?>[];
    final upper = <double?>[];
    final lower = <double?>[];

    for (int i = 0; i < klines.length; i++) {
      if (i < period - 1) {
        middle.add(null);
        upper.add(null);
        lower.add(null);
      } else {
        // 计算SMA
        double sum = 0;
        for (int j = i - period + 1; j <= i; j++) {
          sum += double.tryParse(klines[j].close) ?? 0;
        }
        final sma = sum / period;

        // 计算标准差
        double variance = 0;
        for (int j = i - period + 1; j <= i; j++) {
          final close = double.tryParse(klines[j].close) ?? 0;
          variance += math.pow(close - sma, 2);
        }
        final std = math.sqrt(variance / period);

        middle.add(sma);
        upper.add(sma + stdDev * std);
        lower.add(sma - stdDev * std);
      }
    }

    return {
      'middle': middle,
      'upper': upper,
      'lower': lower,
    };
  }

  /// 计算MACD
  /// 快线周期12，慢线周期26，信号线周期9
  Map<String, List<double?>> calculateMACD({
    int fastPeriod = 12,
    int slowPeriod = 26,
    int signalPeriod = 9,
  }) {
    final dif = <double?>[];
    final dea = <double?>[];
    final macd = <double?>[];

    // 计算快线和慢线EMA
    final fastEma = _calculateSingleEMA(fastPeriod);
    final slowEma = _calculateSingleEMA(slowPeriod);

    // 计算DIF
    for (int i = 0; i < klines.length; i++) {
      if (fastEma[i] == null || slowEma[i] == null) {
        dif.add(null);
      } else {
        dif.add(fastEma[i]! - slowEma[i]!);
      }
    }

    // 计算DEA（DIF的EMA）
    final multiplier = 2.0 / (signalPeriod + 1);
    double? prevDea;

    for (int i = 0; i < dif.length; i++) {
      if (dif[i] == null) {
        dea.add(null);
      } else if (prevDea == null) {
        // 第一个非空DIF作为初始DEA
        prevDea = dif[i];
        dea.add(prevDea);
      } else {
        prevDea = (dif[i]! - prevDea) * multiplier + prevDea;
        dea.add(prevDea);
      }
    }

    // 计算MACD柱
    for (int i = 0; i < dif.length; i++) {
      if (dif[i] == null || dea[i] == null) {
        macd.add(null);
      } else {
        macd.add((dif[i]! - dea[i]!) * 2);
      }
    }

    return {
      'dif': dif,
      'dea': dea,
      'macd': macd,
    };
  }

  List<double?> _calculateSingleEMA(int period) {
    final emaList = <double?>[];
    final multiplier = 2.0 / (period + 1);
    double? prevEma;

    for (int i = 0; i < klines.length; i++) {
      final close = double.tryParse(klines[i].close) ?? 0;

      if (i < period - 1) {
        emaList.add(null);
      } else if (i == period - 1) {
        double sum = 0;
        for (int j = 0; j <= i; j++) {
          sum += double.tryParse(klines[j].close) ?? 0;
        }
        prevEma = sum / period;
        emaList.add(prevEma);
      } else {
        prevEma = (close - prevEma!) * multiplier + prevEma;
        emaList.add(prevEma);
      }
    }

    return emaList;
  }

  /// 计算KDJ
  /// 周期9，K平滑3，D平滑3
  Map<String, List<double?>> calculateKDJ({
    int period = 9,
    int kSmooth = 3,
    int dSmooth = 3,
  }) {
    final k = <double?>[];
    final d = <double?>[];
    final j = <double?>[];

    double? prevK = 50;
    double? prevD = 50;

    for (int i = 0; i < klines.length; i++) {
      if (i < period - 1) {
        k.add(null);
        d.add(null);
        j.add(null);
      } else {
        // 计算周期内最高价和最低价
        double highest = double.negativeInfinity;
        double lowest = double.infinity;
        for (int j = i - period + 1; j <= i; j++) {
          final high = double.tryParse(klines[j].high) ?? 0;
          final low = double.tryParse(klines[j].low) ?? 0;
          if (high > highest) highest = high;
          if (low < lowest) lowest = low;
        }

        final close = double.tryParse(klines[i].close) ?? 0;

        // RSV = (Close - Lowest) / (Highest - Lowest) * 100
        double rsv = 50;
        if (highest != lowest) {
          rsv = (close - lowest) / (highest - lowest) * 100;
        }

        // K = 2/3 * prevK + 1/3 * RSV
        final currentK = (2 * prevK! + rsv) / 3;
        // D = 2/3 * prevD + 1/3 * K
        final currentD = (2 * prevD! + currentK) / 3;
        // J = 3 * K - 2 * D
        final currentJ = 3 * currentK - 2 * currentD;

        k.add(currentK);
        d.add(currentD);
        j.add(currentJ);

        prevK = currentK;
        prevD = currentD;
      }
    }

    return {
      'k': k,
      'd': d,
      'j': j,
    };
  }

  /// 计算RSI
  /// 周期14
  List<double?> calculateRSI({int period = 14}) {
    final rsiList = <double?>[];
    double? prevAvgGain;
    double? prevAvgLoss;

    for (int i = 0; i < klines.length; i++) {
      if (i < period) {
        rsiList.add(null);
      } else if (i == period) {
        // 计算初始平均涨跌幅
        double totalGain = 0;
        double totalLoss = 0;
        for (int j = 1; j <= period; j++) {
          final change = (double.tryParse(klines[j].close) ?? 0) -
              (double.tryParse(klines[j - 1].close) ?? 0);
          if (change > 0) {
            totalGain += change;
          } else {
            totalLoss += -change;
          }
        }
        prevAvgGain = totalGain / period;
        prevAvgLoss = totalLoss / period;

        final rs = prevAvgLoss == 0 ? 100 : prevAvgGain / prevAvgLoss;
        final rsi = 100 - (100 / (1 + rs));
        rsiList.add(rsi);
      } else {
        final change = (double.tryParse(klines[i].close) ?? 0) -
            (double.tryParse(klines[i - 1].close) ?? 0);
        final gain = change > 0 ? change : 0.0;
        final loss = change < 0 ? -change : 0.0;

        prevAvgGain = (prevAvgGain! * (period - 1) + gain) / period;
        prevAvgLoss = (prevAvgLoss! * (period - 1) + loss) / period;

        final rs = prevAvgLoss == 0 ? 100 : prevAvgGain / prevAvgLoss;
        final rsi = 100 - (100 / (1 + rs));
        rsiList.add(rsi);
      }
    }

    return rsiList;
  }
}
