#nullable enable

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;

namespace UVC.Data
{
    /// <summary>
    /// HTTP 요청 파이프라인 정보를 관리하는 클래스입니다.
    /// 요청 URL, 메서드, 헤더, 본문과 같은 HTTP 요청 정보 및 
    /// 반복 실행, 재시도, 데이터 매핑 등 파이프라인 동작을 구성합니다.
    /// </summary>
    /// <remarks>
    /// 이 클래스는 파이프라인 빌더 패턴을 사용하여 HTTP 요청 설정을 구성할 수 있도록 합니다.
    /// 각 설정 메서드는 체이닝을 통해 유연하게 요청을 정의할 수 있습니다.
    /// </remarks>
    /// <example>
    /// <code>
    /// var pipelineInfo = new HttpPipeLineInfo("https://api.example.com/data", "GET")
    ///     .setDataMapper(new DataMapper(dataMask))
    ///     .setSuccessHandler(data => Console.WriteLine(data)) // 성공 핸들러 예시
    ///     .setFailHandler(errorData => Console.Error.WriteLine(errorData)) // 실패 핸들러 예시
    ///     .setRetry(5, 2000)
    ///     .setRepeat(true, 10, 5000);
    /// </code>
    /// </example>
    public class HttpPipeLineInfo
    {
        private string _url;
        private string _method;
        private Dictionary<string, string>? _headers = null;
        private string? _body = null;
        private Action<IDataObject?>? _successhandler = null; //요청 성공 시 호출될 내부 핸들러입니다.
        private Action<string>? _failhandler = null; //요청 실패 시 호출될 내부 핸들러입니다.
        private bool _repeat = false; // 반복 실행 여부
        private int _repeatCount = 0; // 반복 횟수, 0은 무한 반복
        private int _repeatInterval = 1000; // 반복 간격 (ms)
        private DataMapper? _dataMapper = null; // 데이터 매퍼
        private HttpResponseMask _responseMask = new HttpResponseMask(); // response 데이터 성공 여부와 데이터를 구분하는 마스크
        private int _maxRetryCount = 3;
        private int _retryDelay = 1000; // 밀리초
        private bool _updatedDataOnly = false; // 업데이트된 데이터만 받을 여부

        /// <summary>
        /// 요청을 보낼 URL 주소
        /// </summary>
        public string Url => _url;

        /// <summary>
        /// HTTP 요청 메서드 (GET, POST 등)
        /// </summary>
        public string Method => _method;

        /// <summary>
        /// HTTP 요청 헤더
        /// </summary>
        public Dictionary<string, string>? Headers => _headers;

        /// <summary>
        /// HTTP 요청 본문
        /// </summary>
        public string? Body => _body;

        /// <summary>
        /// 요청 성공 시 호출될 핸들러
        /// </summary>
        public Action<IDataObject?>? SuccessHandler => _successhandler;

        /// <summary>
        /// 요청 실패 시 호출될 핸들러
        /// </summary>
        public Action<string>? FailHandler => _failhandler;

        /// <summary>
        /// 반복 실행 여부
        /// </summary>
        public bool Repeat => _repeat;

        /// <summary>
        /// 반복 횟수, 0은 무한 반복
        /// </summary>
        public int RepeatCount => _repeatCount;

        /// <summary>
        /// 반복 간격 (ms)
        /// </summary>
        public int RepeatInterval => _repeatInterval;

        /// <summary>
        /// 데이터 매퍼 객체
        /// </summary>
        public DataMapper? DataMapper => _dataMapper;

        /// <summary>
        /// HTTP 응답의 성공 여부를 확인하고, 성공 시 실제 데이터 페이로드를 추출하는 데 사용되는 <see cref="Data.HttpResponseMask"/>입니다.
        /// 이 객체에 정의된 규칙에 따라 원시 응답 문자열이 처리됩니다.
        /// </summary>
        public HttpResponseMask ResponseMask => _responseMask;

        /// <summary>
        /// 최대 재시도 횟수
        /// </summary>
        public int MaxRetryCount => _maxRetryCount;

        /// <summary>
        /// 재시도 간격 (ms)
        /// </summary>
        public int RetryDelay => _retryDelay;

        /// <summary>
        /// 업데이트된 데이터만 받을 여부 (true로 설정하면, 데이터가 변경된 경우에만 핸들러가 호출됩니다)
        /// </summary>
        public bool UpdatedDataOnly => _updatedDataOnly;

        /// <summary>
        /// HttpPipeLineInfo 클래스의 새 인스턴스를 초기화합니다.
        /// </summary>
        /// <param name="url">HTTP 요청을 보낼 URL</param>
        /// <param name="method">HTTP 요청 메서드 (기본값: "post")</param>
        /// <param name="headers">HTTP 요청 헤더 (선택사항)</param>
        /// <param name="body">HTTP 요청 본문 (선택사항)</param>
        public HttpPipeLineInfo(string url, string method = "post", Dictionary<string, string>? headers = null, string? body = null)
        {
            _url = url;
            _method = method;
            _headers = headers;
            _body = body;
        }

        /// <summary>
        /// HTTP 요청 응답을 처리할 데이터 매퍼를 설정합니다.
        /// 데이터 매퍼는 HTTP 응답을 IDataObject로 변환하는 역할을 합니다.
        /// </summary>
        /// <param name="dataMapper">사용할 데이터 매퍼 객체</param>
        /// <returns>현재 HttpPipeLineInfo 인스턴스 (메서드 체이닝용)</returns>
        public HttpPipeLineInfo setDataMapper(DataMapper dataMapper)
        {
            _dataMapper = dataMapper;
            return this;
        }

        /// <summary>
        /// HTTP 파이프라인에 적용할 ResponseMask를 설정하고 업데이트된 파이프라인 구성을 반환합니다.
        /// </summary>
        /// <param name="responseMask">HTTP response에 적용할 <see cref="HttpResponseMask"/>입니다.</param>
        /// <returns>지정된 response 마스크가 적용된 업데이트된 <see cref="HttpPipeLineInfo"/> 인스턴스입니다.</returns>
        public HttpPipeLineInfo setResponseMask(HttpResponseMask responseMask)
        {
            _responseMask = responseMask;
            return this;
        }

        /// <summary>
        /// HTTP 요청이 완료된 후 호출될 핸들러를 설정합니다.
        /// 변경 된 데이터는 IDataObject로 전달됩니다.
        /// UpdatedDataOnly=true일 경우 변경 된 데이터가 없으면 호출 되지 않습니다.
        /// </summary>
        /// <param name="handler">응답 데이터를 처리할 콜백 함수</param>
        /// <returns>현재 HttpPipeLineInfo 인스턴스 (메서드 체이닝용)</returns>
        public HttpPipeLineInfo setSuccessHandler(Action<IDataObject?>? handler)
        {
            _successhandler = handler;
            return this;
        }

        /// <summary>
        /// HTTP 요청이 실패했을 때 호출될 핸들러를 설정합니다.
        /// 실패 정보 또는 관련 데이터가 string 형태로 전달될 수 있습니다.
        /// </summary>
        /// <param name="handler">실패 정보를 처리할 콜백 함수입니다. 실패 시 관련 데이터를 인자로 받습니다.</param>
        /// <returns>현재 HttpPipeLineInfo 인스턴스 (메서드 체이닝용)</returns>
        public HttpPipeLineInfo setFailHandler(Action<string>? handler)
        {
            _failhandler = handler;
            return this;
        }

        /// <summary>
        /// HTTP 요청 실패 시 재시도 정책을 설정합니다.
        /// </summary>
        /// <param name="maxRetryCount">최대 재시도 횟수 (기본값: 3)</param>
        /// <param name="retryDelay">재시도 간 대기 시간(밀리초) (기본값: 1000)</param>
        /// <returns>현재 HttpPipeLineInfo 인스턴스 (메서드 체이닝용)</returns>
        public HttpPipeLineInfo setRetry(int maxRetryCount = 3, int retryDelay = 1000)
        {
            _maxRetryCount = maxRetryCount;
            _retryDelay = retryDelay;
            return this;
        }

        /// <summary>
        /// HTTP 요청의 반복 실행 설정을 구성합니다.
        /// </summary>
        /// <param name="repeat">반복 실행 여부</param>
        /// <param name="count">반복 횟수 (0은 무한 반복) (기본값: 0)</param>
        /// <param name="interval">반복 실행 간 대기 시간(밀리초) (기본값: 1000)</param>
        /// <param name="updatedDataOnly">변경된 데이터만 처리할지 여부 (기본값: true)</param>
        /// <returns>현재 HttpPipeLineInfo 인스턴스 (메서드 체이닝용)</returns>
        /// <remarks>
        /// 반복 요청 시 updatedDataOnly가 true인 경우, 서버 응답에서 데이터가 변경된 경우에만 핸들러가 호출됩니다.
        /// 이는 불필요한 데이터 처리를 방지하고 성능을 향상시키는 데 도움이 됩니다.
        /// </remarks>
        /// <example>
        /// <code>
        /// // 5초마다 10번 반복 요청, 변경된 데이터만 처리
        /// var pipelineInfo = new HttpPipeLineInfo("https://api.example.com/data", "GET")
        ///     .setHandler(data => ProcessData(data))
        ///     .setRepeat(true, 10, 5000, true);
        ///     
        /// // 3초마다 무한 반복, 모든 응답 데이터 처리
        /// var pipelineInfo = new HttpPipeLineInfo("https://api.example.com/status", "GET")
        ///     .setHandler(data => UpdateStatus(data))
        ///     .setRepeat(true, 0, 3000, false);
        /// </code>
        /// </example>
        public HttpPipeLineInfo setRepeat(bool repeat, int count = 0, int interval = 1000, bool updatedDataOnly = true)
        {
            _repeat = repeat;
            _repeatCount = count;
            _repeatInterval = interval;
            _updatedDataOnly = updatedDataOnly; // true로 설정하면, 데이터가 변경된 경우에만 핸들러가 호출됩니다.
            return this;
        }

    }
}
