using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using com.itac.mes.imsapi.protocol;

namespace com.itac.mes.imsapi.transport
{
    internal sealed class IhapLocator
    {
        private readonly HttpClient _http;
        private readonly IhapClientOptions _options;
        public IhapLocator(HttpClient http,IhapClientOptions options){_http=http;_options=options;}

        public async Task<string> ResolveAsync(CancellationToken ct, string skipBase = null)
        {
            if(!string.IsNullOrWhiteSpace(_options.ServiceUrl)) return NormalizeServiceUrl(_options.ServiceUrl);
            Exception last=null;
            foreach(var raw in _options.ClusterNodes)
            {
                if(string.IsNullOrWhiteSpace(raw)) continue;
                string b=NormalizeBaseUrl(raw);
                if(skipBase!=null && b.Equals(skipBase,StringComparison.OrdinalIgnoreCase))continue;
                try
                {
                    string host=Dns.GetHostName();
                    int pid=Process.GetCurrentProcess().Id;
                    string q="service="+Uri.EscapeDataString("/imsapi/service")+
                        "&appid="+Uri.EscapeDataString(_options.AppId??"IMSApiDotNet")+
                        (string.IsNullOrEmpty(_options.AppType)?"":"&apptype="+Uri.EscapeDataString(_options.AppType))+
                        "&host="+Uri.EscapeDataString(host)+"&pid="+pid.ToString(System.Globalization.CultureInfo.InvariantCulture)+
                        (_options.IgnoreNetworkPrefix?"&nogroupnat=true":"");
                    using(var lookup=await _http.GetAsync(b+"/artes/lookup?"+q,ct).ConfigureAwait(false))
                    {
                        if(!lookup.IsSuccessStatusCode) continue;
                        string body=await lookup.Content.ReadAsStringAsync().ConfigureAwait(false);
                        if(!ContainsService(body)) continue;
                    }
                    string service=b+"/imsapi/service";
                    try
                    {
                        using(var ping=await _http.GetAsync(service+"?type=machine",ct).ConfigureAwait(false))
                        {
                            if(ping.IsSuccessStatusCode)
                            {
                                string state=await ping.Content.ReadAsStringAsync().ConfigureAwait(false);
                                if(state.IndexOf("REGISTERED",StringComparison.OrdinalIgnoreCase)>=0 || state.Length==0) return service;
                            }
                        }
                    }
                    catch { /* POST itself is authoritative; lookup already succeeded. */ }
                    return service;
                }
                catch(Exception ex){last=ex;}
            }
            throw new IhapCommunicationException("No IMSAPI service could be resolved from itac.artes.clusternodes.",last);
        }
        private static bool ContainsService(string xml)
        {
            if(string.IsNullOrWhiteSpace(xml)) return true;
            try { var d=XDocument.Parse(xml); return d.Descendants().Any(x=>x.Name.LocalName.Equals("service",StringComparison.OrdinalIgnoreCase)); }
            catch { return xml.IndexOf("imsapi",StringComparison.OrdinalIgnoreCase)>=0 || xml.IndexOf("service",StringComparison.OrdinalIgnoreCase)>=0; }
        }
        private static string NormalizeBaseUrl(string u)
        {
            u=(u??string.Empty).Trim().TrimEnd('/');
            if(u.Length==0) return u;
            if(!u.StartsWith("http://",StringComparison.OrdinalIgnoreCase) &&
               !u.StartsWith("https://",StringComparison.OrdinalIgnoreCase)) u="http://"+u;
            return u;
        }
        private static string NormalizeServiceUrl(string u)
        {
            u=NormalizeBaseUrl(u);
            return u.EndsWith("/imsapi/service",StringComparison.OrdinalIgnoreCase)?u:u+"/imsapi/service";
        }
    }
}
