//  
//   Rebex Sample Code License
// 
//   Copyright 2026, REBEX CR s.r.o.
//   All rights reserved.
//   https://www.rebex.net/
// 
//   Permission to use, copy, modify, and/or distribute this software for any
//   purpose with or without fee is hereby granted.
// 
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//   OTHER DEALINGS IN THE SOFTWARE.
// 

using System;
using System.Collections.Generic;
using System.Linq;

namespace Rebex.Samples
{
    /// <summary>
    /// Simple wrapper for an HTTP response.
    /// </summary>
    public class SimpleHttpResponse
    {
        private const int FIRST_LINE_PARTS = 3;
        private const string HEADER_LINE_SEPARATOR = "\r\n";
        private const char SPACE_SEPARATOR = ' ';
        private const char HEADER_SEPARATOR = ':';
        private static readonly char[] HEADER_SEPARATOR_IN_ARRAY = { HEADER_SEPARATOR };
        private static readonly char[] SPACE_SEPARATOR_IN_ARRAY = { SPACE_SEPARATOR };
        private const string INVALID_HTTP_HEADERS_ERROR = "Invalid http headers.";
        private const string UNEXPECTED_STATUS_LINE_ERROR = "Unexpected status line.";
        private static readonly string[] HEADER_LINE_SEPARATOR_ARRAY = { HEADER_LINE_SEPARATOR };
        private const string CONTENT_LENGTH_HEADER = "content-length";
        private const string CONTENT_TYPE_HEADER = "content-type";
        private const string LOCATION_HEADER = "location";
        private const int HTTP_NOT_FOUND_ERROR = 404;
        private const string DEFAULT_CONTENT_TYPE = "application/octet-stream";

        public SimpleHttpResponse(string currentHttpResponseHeaders)
        {
            if (string.IsNullOrEmpty(currentHttpResponseHeaders))
            {
                throw new ArgumentException("Value cannot be null or empty.", nameof(currentHttpResponseHeaders));
            }

            RawHttpResponseHeaders = currentHttpResponseHeaders;
            ContentLength = null;
            ParseRawData();
        }

        public string StatusMessage
        {
            get;
            set;
        }

        public int StatusCode
        {
            get;
            private set;
        }

        public string ProtocolVersion
        {
            get;
            private set;
        }

        public ILookup<string, string> Headers
        {
            get;
            private set;
        }

        public long? ContentLength
        {
            get;
            private set;
        }

        public bool IsOkResponse => StatusCode >= 200 && StatusCode < 300;

        public bool IsErrorResponse => StatusCode >= 400 && StatusCode < 600;

        public bool IsRedirectResponse => StatusCode >= 300 && StatusCode < 400;

        public string RawHttpResponseHeaders
        {
            get;
        }

        public bool IsNotFoundError => StatusCode == HTTP_NOT_FOUND_ERROR;

        public string ContentType
        {
            get;
            private set;
        }

        public string Location
        {
            get
            {
                return TryGetHeaderValue(LOCATION_HEADER, string.Empty);
            }
        }

        public string TryGetHeaderValue(string headerName, string defaultValue)
        {
            var values = Headers[headerName.ToLowerInvariant()];
            return values.Any() ? values.First().Trim() : defaultValue;
        }

        private void ParseRawData()
        {
            try
            {
                var currentHeaderLines = RawHttpResponseHeaders.Split(HEADER_LINE_SEPARATOR_ARRAY, StringSplitOptions.RemoveEmptyEntries);
                if (RawHttpResponseHeaders.Length == 0)
                {
                    throw new HttpParserException(INVALID_HTTP_HEADERS_ERROR);
                }

                var firstResponseLine = currentHeaderLines[0].Split(SPACE_SEPARATOR_IN_ARRAY, FIRST_LINE_PARTS);
                if (firstResponseLine.Length < FIRST_LINE_PARTS)
                {
                    throw new HttpParserException(UNEXPECTED_STATUS_LINE_ERROR);
                }

                ProtocolVersion = firstResponseLine[0];
                StatusCode = int.Parse(firstResponseLine[1]);
                StatusMessage = firstResponseLine[2];
                Headers = currentHeaderLines.Skip(1)
                    .Select(rawHeader => rawHeader.Split(HEADER_SEPARATOR_IN_ARRAY, 2, StringSplitOptions.None))
                    .ToLookup(header => header[0].ToLowerInvariant(), header => header[1].Trim('\'', '"'));

                string contentLength = TryGetHeaderValue(CONTENT_LENGTH_HEADER, null);
                if (contentLength != null)
                {
                    ContentLength = long.Parse(contentLength);
                }

                ContentType = TryGetHeaderValue(CONTENT_TYPE_HEADER, DEFAULT_CONTENT_TYPE);
            }
            catch (Exception ex)
            {
                throw new HttpParserException(INVALID_HTTP_HEADERS_ERROR, ex);
            }
        }
    }
}
