using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;
using System.Net.Http;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Windows;

namespace AxCopilot.Handlers;

// ─── 수식 파서 ─────────────────────────────────────────────────────────────────

/// <summary>
/// 재귀 하강 파서 기반 수학 수식 평가기.
/// 지원: +, -, *, /, %, ^ (거듭제곱), 괄호, 단항 음수,
///        sqrt, abs, ceil, floor, round, sin, cos, tan (도 단위),
///        log (밑 10), ln (자연로그), pi, e
/// </summary>
internal static class MathEvaluator
{
    public static double Evaluate(string expr)
    {
        var evaluator = new Evaluator(
            expr.Replace(" ", "")
                .Replace("×", "*")
                .Replace("÷", "/")
                .Replace("，", ",")
                .ToLowerInvariant());
        return evaluator.Parse();
    }

    private class Evaluator
    {
        private readonly string _s;
        private int _i;

        public Evaluator(string s) { _s = s; _i = 0; }

        public double Parse()
        {
            var result = ParseExpr();
            if (_i < _s.Length)
                throw new InvalidOperationException($"예기치 않은 문자: '{_s[_i]}'");
            return result;
        }

        // 덧셈 / 뺄셈
        private double ParseExpr()
        {
            var left = ParseTerm();
            while (_i < _s.Length && (_s[_i] == '+' || _s[_i] == '-'))
            {
                var op = _s[_i++];
                var right = ParseTerm();
                left = op == '+' ? left + right : left - right;
            }
            return left;
        }

        // 곱셈 / 나눗셈 / 나머지
        private double ParseTerm()
        {
            var left = ParsePower();
            while (_i < _s.Length && (_s[_i] == '*' || _s[_i] == '/' || _s[_i] == '%'))
            {
                var op = _s[_i++];
                var right = ParsePower();
                left = op == '*' ? left * right
                     : op == '/' ? left / right
                     : left % right;
            }
            return left;
        }

        // 거듭제곱 (오른쪽 결합)
        private double ParsePower()
        {
            var b = ParseUnary();
            if (_i < _s.Length && _s[_i] == '^')
            {
                _i++;
                var exp = ParseUnary();
                return Math.Pow(b, exp);
            }
            return b;
        }

        // 단항 부호
        private double ParseUnary()
        {
            if (_i < _s.Length && _s[_i] == '-') { _i++; return -ParsePrimary(); }
            if (_i < _s.Length && _s[_i] == '+') { _i++; return ParsePrimary(); }
            return ParsePrimary();
        }

        // 리터럴 / 괄호 / 함수 호출
        private double ParsePrimary()
        {
            if (_i >= _s.Length)
                throw new InvalidOperationException("수식이 불완전합니다.");

            // 16진수 리터럴 0x...
            if (_i + 1 < _s.Length && _s[_i] == '0' && _s[_i + 1] == 'x')
            {
                _i += 2;
                var hexStart = _i;
                while (_i < _s.Length && "0123456789abcdef".Contains(_s[_i])) _i++;
                return Convert.ToInt64(_s[hexStart.._i], 16);
            }

            // 숫자
            if (char.IsDigit(_s[_i]) || _s[_i] == '.')
            {
                var start = _i;
                while (_i < _s.Length && (char.IsDigit(_s[_i]) || _s[_i] == '.')) _i++;
                // 과학적 표기: 1.5e3
                if (_i < _s.Length && _s[_i] == 'e')
                {
                    _i++;
                    if (_i < _s.Length && (_s[_i] == '+' || _s[_i] == '-')) _i++;
                    while (_i < _s.Length && char.IsDigit(_s[_i])) _i++;
                }
                return double.Parse(_s[start.._i],
                    System.Globalization.NumberStyles.Float,
                    System.Globalization.CultureInfo.InvariantCulture);
            }

            // 괄호
            if (_s[_i] == '(')
            {
                _i++;
                var val = ParseExpr();
                if (_i < _s.Length && _s[_i] == ')') _i++;
                return val;
            }

            // 식별자 (상수 또는 함수)
            if (char.IsLetter(_s[_i]))
            {
                var start = _i;
                while (_i < _s.Length && (char.IsLetterOrDigit(_s[_i]) || _s[_i] == '_')) _i++;
                var name = _s[start.._i];

                // 상수
                if (name == "pi")  return Math.PI;
                if (name == "e")   return Math.E;
                if (name == "inf") return double.PositiveInfinity;

                // 함수 호출
                if (_i < _s.Length && _s[_i] == '(')
                {
                    _i++; // (
                    var arg = ParseExpr();
                    // 두 번째 인자 (pow, log2 등)
                    double? arg2 = null;
                    if (_i < _s.Length && _s[_i] == ',')
                    {
                        _i++;
                        arg2 = ParseExpr();
                    }
                    if (_i < _s.Length && _s[_i] == ')') _i++;

                    return name switch
                    {
                        "sqrt"  => Math.Sqrt(arg),
                        "abs"   => Math.Abs(arg),
                        "ceil"  => Math.Ceiling(arg),
                        "floor" => Math.Floor(arg),
                        "round" => arg2.HasValue ? Math.Round(arg, (int)arg2.Value) : Math.Round(arg),
                        "sin"   => Math.Sin(arg * Math.PI / 180),   // 도 단위
                        "cos"   => Math.Cos(arg * Math.PI / 180),
                        "tan"   => Math.Tan(arg * Math.PI / 180),
                        "asin"  => Math.Asin(arg) * 180 / Math.PI,
                        "acos"  => Math.Acos(arg) * 180 / Math.PI,
                        "atan"  => Math.Atan(arg) * 180 / Math.PI,
                        "log"   => arg2.HasValue ? Math.Log(arg, arg2.Value) : Math.Log10(arg),
                        "log2"  => Math.Log2(arg),
                        "ln"    => Math.Log(arg),
                        "exp"   => Math.Exp(arg),
                        "pow"   => arg2.HasValue ? Math.Pow(arg, arg2.Value) : throw new InvalidOperationException("pow(x,y) 형식으로 사용하세요."),
                        "min"   => arg2.HasValue ? Math.Min(arg, arg2.Value) : arg,
                        "max"   => arg2.HasValue ? Math.Max(arg, arg2.Value) : arg,
                        _       => throw new InvalidOperationException($"알 수 없는 함수: {name}()")
                    };
                }

                throw new InvalidOperationException($"알 수 없는 식별자: {name}");
            }

            throw new InvalidOperationException($"예기치 않은 문자: '{_s[_i]}'");
        }
    }
}
