using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Drawing;
using Matriks.Data.Identifiers;
using Matriks.Data.Symbol;
using Matriks.Engines;
using Matriks.Indicators;
using Matriks.Symbols;
using Matriks.AlgoTrader;
using Matriks.Trader.Core;
using Matriks.Trader.Core.Fields;
using Matriks.Trader.Core.TraderModels;
using Matriks.Lean.Algotrader.AlgoBase;
using Matriks.Lean.Algotrader.Models;
using Matriks.Lean.Algotrader.Trading;

namespace Matriks.Lean.Algotrader
{
    [IndicatorInformationAttribute("WaveTrend", IndicatorDrawingArea.NewWindow)]
    [IndicatorLineInformationAttribute(new[]
    {
        "WT1",
        "WT2",
        "Zero Line",
        "OB Level 1",
        "OS Level 1",
        "OB Level 2",
        "OS Level 2"
    })]

    public class WaveTrend : MatriksIndicator
    {
        [DefaultValue(10)]
        public int ChannelLength { get; set; }

        [DefaultValue(21)]
        public int AverageLength { get; set; }

        [DefaultValue(60)]
        public decimal OverBoughtLevel1 { get; set; }

        [DefaultValue(53)]
        public decimal OverBoughtLevel2 { get; set; }

        [DefaultValue(-60)]
        public decimal OverSoldLevel1 { get; set; }

        [DefaultValue(-53)]
        public decimal OverSoldLevel2 { get; set; }

        public sealed override void OnInit()
        {
            for (int i = 0; i < 7; i++)
            {
                SetLine(i, 0);
            }
        }

        public override void OnDataUpdate(int currentBar, decimal inputValue, DateTime barDateTime)
        {
            if (currentBar < Math.Max(ChannelLength, AverageLength))
            {
                for (int i = 0; i < 7; i++)
                {
                    SetLine(i, currentBar, 0);
                }
                return;
            }

            decimal ap = GetHL3(currentBar);
            decimal esa = GetEMA(ap, ChannelLength, currentBar);
            decimal d = GetEMA(Math.Abs(ap - esa), ChannelLength, currentBar);
            decimal ci = (ap - esa) / (0.015m * d);
            decimal tci = GetEMA(ci, AverageLength, currentBar);

            decimal wt1 = tci;
            decimal wt2 = GetSMA(wt1, 4, currentBar);

            SetLine(0, currentBar, wt1, Color.Green); // WT1
            SetLine(1, currentBar, wt2, Color.Red); // WT2
            SetLine(2, currentBar, 0, Color.Gray); // Zero Line
            SetLine(3, currentBar, OverBoughtLevel1, Color.Red); // OB Level 1
            SetLine(4, currentBar, OverSoldLevel1, Color.Green); // OS Level 1
            SetLine(5, currentBar, OverBoughtLevel2, Color.Red); // OB Level 2
            SetLine(6, currentBar, OverSoldLevel2, Color.Green); // OS Level 2

            // Plot crosses
            if (Cross(wt1, wt2, currentBar))
            {
                SetLine(1, currentBar, wt2, Color.Black, LineStyle.Circles, 3);
                SetLine(1, currentBar, wt2, (wt2 - wt1 > 0 ? Color.Red : Color.Lime), LineStyle.Circles, 2);
            }

            // Bar coloring
            if (Cross(wt1, wt2, currentBar))
            {
                BarColor(currentBar, wt2 - wt1 > 0 ? Color.Aqua : Color.Yellow);
            }
        }

        private decimal GetHL3(int currentBar)
        {
            return (Instrument.SymbolBarData.High[currentBar] + Instrument.SymbolBarData.Low[currentBar] + Instrument.SymbolBarData.Close[currentBar]) / 3;
        }

        private decimal GetEMA(decimal value, int period, int currentBar)
        {
            decimal k = 2m / (period + 1);
            decimal ema = value;
            for (int i = 1; i <= period && currentBar - i >= 0; i++)
            {
                ema = (value * k) + (ema * (1 - k));
            }
            return ema;
        }

        private decimal GetSMA(decimal value, int period, int currentBar)
        {
            decimal sum = 0;
            for (int i = 0; i < period && currentBar - i >= 0; i++)
            {
                sum += value;
            }
            return sum / period;
        }

        private bool Cross(decimal series1, decimal series2, int currentBar)
        {
            return (series1 > series2 && GetPreviousValue(series1, currentBar) <= GetPreviousValue(series2, currentBar)) ||
                   (series1 < series2 && GetPreviousValue(series1, currentBar) >= GetPreviousValue(series2, currentBar));
        }

        private decimal GetPreviousValue(decimal value, int currentBar)
        {
            return currentBar > 0 ? value : 0;
        }

        private void BarColor(int currentBar, Color color)
        {
            // Implement bar coloring logic here
        }

        private void SetLine(int index, int currentBar, decimal value, Color color = default, LineStyle style = default, int lineWidth = 1)
        {
            // Implement line setting logic here
            // This is a placeholder implementation. You need to replace it with actual logic to set the line properties.
            Console.WriteLine($"Setting line {index} at bar {currentBar} with value {value}, color {color}, style {style}, lineWidth {lineWidth}");
        }
    }

    public enum LineStyle
    {
        Solid,
        Dotted,
        Dashed,
        Circles
    }
}