using MaxwellFramework.Core.Attributes;
using System;
using System.Collections.Generic;

namespace MainShell.Hardware.Acs
{
    [Singleton]
    public sealed class AcsAddressRepository
    {
        private readonly object _syncRoot = new object();
        private readonly Dictionary<string, AcsBondingCommunicationAdress> _bondingCommunicationDataCache = new Dictionary<string, AcsBondingCommunicationAdress>(StringComparer.Ordinal);
        private readonly Dictionary<string, AcsBondingLogAdress> _bondingLogDataCache = new Dictionary<string, AcsBondingLogAdress>(StringComparer.Ordinal);
        private readonly Lazy<AcsCommonAdress> _commonData = new Lazy<AcsCommonAdress>(() => new AcsCommonAdress());
        private readonly Lazy<AcsInterferometerCompensationAdress> _interferometerCompensationData = new Lazy<AcsInterferometerCompensationAdress>(() => new AcsInterferometerCompensationAdress());
        private readonly Lazy<AcsHomeOffsetAdress> _homeOffsetData = new Lazy<AcsHomeOffsetAdress>(() => new AcsHomeOffsetAdress());
        private readonly Lazy<AcsHomeSettingAdress> _homeSettingData = new Lazy<AcsHomeSettingAdress>(() => new AcsHomeSettingAdress());
        private readonly Lazy<AcsBondingAdress> _newBondingData = new Lazy<AcsBondingAdress>(() => new AcsBondingAdress());

        public AcsBondingCommunicationAdress GetBondingCommunicationData(string addressSuffix)
        {
            string normalizedSuffix = NormalizeAddressSuffix(addressSuffix);
            AcsBondingCommunicationAdress communicationData;
            if (_bondingCommunicationDataCache.TryGetValue(normalizedSuffix, out communicationData))
            {
                return communicationData;
            }

            lock (_syncRoot)
            {
                if (_bondingCommunicationDataCache.TryGetValue(normalizedSuffix, out communicationData))
                {
                    return communicationData;
                }

                communicationData = new AcsBondingCommunicationAdress(normalizedSuffix);
                _bondingCommunicationDataCache[normalizedSuffix] = communicationData;
                return communicationData;
            }
        }

        public AcsBondingLogAdress GetBondingLogData(string addressSuffix)
        {
            string normalizedSuffix = NormalizeAddressSuffix(addressSuffix);
            AcsBondingLogAdress logData;
            if (_bondingLogDataCache.TryGetValue(normalizedSuffix, out logData))
            {
                return logData;
            }

            lock (_syncRoot)
            {
                if (_bondingLogDataCache.TryGetValue(normalizedSuffix, out logData))
                {
                    return logData;
                }

                logData = new AcsBondingLogAdress(normalizedSuffix);
                _bondingLogDataCache[normalizedSuffix] = logData;
                return logData;
            }
        }

        public AcsInterferometerCompensationAdress GetInterferometerCompensationData()
        {
            return _interferometerCompensationData.Value;
        }

        public AcsCommonAdress GetCommonData()
        {
            return _commonData.Value;
        }

        public AcsHomeOffsetAdress GetHomeOffsetData()
        {
            return _homeOffsetData.Value;
        }

        public AcsHomeSettingAdress GetHomeSettingData()
        {
            return _homeSettingData.Value;
        }

        public AcsBondingAdress GetNewBondingData()
        {
            return _newBondingData.Value;
        }

        private static string NormalizeAddressSuffix(string addressSuffix)
        {
            if (addressSuffix == null)
            {
                throw new ArgumentNullException(nameof(addressSuffix));
            }

            string normalizedSuffix = addressSuffix.Trim();
            if (normalizedSuffix.Length == 0)
            {
                throw new ArgumentException("ACS address suffix cannot be empty.", nameof(addressSuffix));
            }

            return normalizedSuffix;
        }
    }
}
