using MySqlConnector;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Dvb.Psi.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static skyscraper5.Dvb.Descriptors.LinkageDescriptor;

namespace skyscraper5.Data.MySql
{
    partial class MySqlDataStorage
    {
        private void InsertSdtLinkages(MySqlConnection connection, Guid source, ICollection<LinkageDescriptor> Linkages, MySqlTransaction transaction)
        {
            if (Linkages == null)
                return;

            if (Linkages.Count == 0)
                return;

            MySqlCommand mySqlCommand = connection.CreateCommand();
            mySqlCommand.Transaction = transaction;
            mySqlCommand.CommandText = "INSERT INTO dvb_linkages " +
                                       "    (uuid, linkage_type, handover_type, handover_origin_type, handover_network_id, handover_initial_service_id, target_event_id, target_event_listed, target_event_simulcasted, table_type, private_data_bytes, bouquet_id, original_network_id, transport_stream_id, service_id) " +
                                       "VALUES " +
                                       "    (@uuid, @linkage_type, @handover_type,@handover_origin_type,@handover_network_id,@handover_initial_service_id,@target_event_id,@target_event_listed,@target_event_simulcasted,@target_type,@private_data_bytes, @bouquet_id, @original_network_id, @transport_stream_id, @service_id)";
            mySqlCommand.Parameters.Add("@uuid", MySqlDbType.VarChar);
            mySqlCommand.Parameters.Add("@linkage_type", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@handover_type", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@handover_origin_type", MySqlDbType.Bool);
            mySqlCommand.Parameters.Add("@handover_network_id", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@handover_initial_service_id", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@target_event_id", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@target_event_listed", MySqlDbType.Bool);
            mySqlCommand.Parameters.Add("@target_event_simulcasted", MySqlDbType.Bool);
            mySqlCommand.Parameters.Add("@target_type", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@private_data_bytes", MySqlDbType.TinyBlob);
            mySqlCommand.Parameters.Add("@bouquet_id", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@original_network_id", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@transport_stream_id", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@service_id", MySqlDbType.Int32);
            mySqlCommand.Parameters["@uuid"].Value = source.ToString();
            foreach (LinkageDescriptor linkageDescriptor in Linkages)
            {
                if (TestForLinkage(transaction, source, linkageDescriptor.LinkageType, linkageDescriptor.OriginalNetworkId, linkageDescriptor.TransportStreamId, linkageDescriptor.ServiceId))
                    continue;

                mySqlCommand.Parameters["@linkage_type"].Value = (int)linkageDescriptor.LinkageType;
                mySqlCommand.Parameters["@handover_type"].Value = linkageDescriptor.HandoverType;
                mySqlCommand.Parameters["@handover_origin_type"].Value = linkageDescriptor.HandoverOriginType;
                mySqlCommand.Parameters["@handover_network_id"].Value = linkageDescriptor.HandoverNetworkId;
                mySqlCommand.Parameters["@handover_initial_service_id"].Value = linkageDescriptor.HandoverInitialServiceId;
                mySqlCommand.Parameters["@target_event_id"].Value = linkageDescriptor.TargetEventId;
                mySqlCommand.Parameters["@target_event_listed"].Value = linkageDescriptor.TargetEventListed;
                mySqlCommand.Parameters["@target_event_simulcasted"].Value = linkageDescriptor.TargetEventSimulcasted;
                mySqlCommand.Parameters["@target_type"].Value = (int)linkageDescriptor.TableType;
                mySqlCommand.Parameters["@private_data_bytes"].Value = linkageDescriptor.PrivateDataBytes;
                mySqlCommand.Parameters["@bouquet_id"].Value = linkageDescriptor.BouquetId;
                mySqlCommand.Parameters["@original_network_id"].Value = linkageDescriptor.OriginalNetworkId;
                mySqlCommand.Parameters["@transport_stream_id"].Value = linkageDescriptor.TransportStreamId;
                mySqlCommand.Parameters["@service_id"].Value = linkageDescriptor.ServiceId;
                SetNulls(mySqlCommand);
                mySqlCommand.ExecuteNonQuery();

                InsertSdtLinkageExtendedEvent(connection, source, linkageDescriptor);
                InsertSdtLinkageIpMac(connection, source, linkageDescriptor);
                InsertSdtLinkageSsu(transaction, source, linkageDescriptor);
            }
        }

        private bool TestForLinkage(MySqlTransaction transaction, Guid source, LinkageDescriptor.LinkageTypeEnum linkageDescriptorLinkageType, ushort linkageDescriptorOriginalNetworkId, ushort linkageDescriptorTransportStreamId, ushort linkageDescriptorServiceId)
        {
            MySqlCommand command = transaction.Connection.CreateCommand();
            command.Transaction = transaction;
            command.CommandText =
                "SELECT dateadded FROM dvb_linkages WHERE uuid = @uuid AND linkage_type = @linkage_type AND original_network_id = @original_network_id " +
                "AND transport_stream_id = @transport_stream_id AND service_id = @service_id";
            command.Parameters.AddWithValue("@uuid", source.ToString());
            command.Parameters.AddWithValue("@linkage_type", (int)linkageDescriptorLinkageType);
            command.Parameters.AddWithValue("@original_network_id", linkageDescriptorOriginalNetworkId);
            command.Parameters.AddWithValue("@transport_stream_id", linkageDescriptorTransportStreamId);
            command.Parameters.AddWithValue("@service_id", linkageDescriptorServiceId);
            MySqlDataReader dataReader = command.ExecuteReader();
            bool result = dataReader.Read();
            dataReader.Close();
            return result;
        }

        private void InsertSdtLinkageSsu(MySqlTransaction transaction, Guid source, LinkageDescriptor linkageDescriptor)
        {
            if (linkageDescriptor.SystemSoftwareUpdateLinkStructure == null)
                return;

            if (linkageDescriptor.SystemSoftwareUpdateLinkStructure.Count == 0)
                return;

            MySqlCommand mySqlCommand = transaction.Connection.CreateCommand();
            mySqlCommand.Transaction = transaction;
            mySqlCommand.CommandText =
                "INSERT INTO dvb_linkages_ssu (uuid, oui, selector) VALUES (@uuid, @oui, @selector)";
            mySqlCommand.Parameters.Add("@uuid", MySqlDbType.VarChar);
            mySqlCommand.Parameters.Add("@oui", MySqlDbType.VarChar);
            mySqlCommand.Parameters.Add("@selector", MySqlDbType.TinyBlob);
            mySqlCommand.Parameters["@uuid"].Value = source.ToString();
            foreach (LinkageDescriptor.OuiPrivateData ouiPrivateData in linkageDescriptor.SystemSoftwareUpdateLinkStructure)
            {
                if (!TestForLinkageSsu(transaction, source, ouiPrivateData.OUI))
                {
                    mySqlCommand.Parameters["@oui"].Value = BitConverter.ToString(ouiPrivateData.OUI);
                    mySqlCommand.Parameters["@selector"].Value = ouiPrivateData.Selector;
                    mySqlCommand.ExecuteNonQuery();
                }
            }
        }

        private bool TestForLinkageSsu(MySqlTransaction transaction, Guid uuid, byte[] oui)
        {
            MySqlCommand command = transaction.Connection.CreateCommand();
            command.Transaction = transaction;
            command.CommandText = "SELECT dateadded FROM dvb_linkages_ssu WHERE uuid = @uuid AND oui = @oui";
            command.Parameters.AddWithValue("@uuid", uuid.ToString());
            command.Parameters.AddWithValue("@oui", BitConverter.ToString(oui));
            MySqlDataReader dataReader = command.ExecuteReader();
            bool result = dataReader.Read();
            dataReader.Close();
            return result;
        }

        private void InsertSdtLinkageIpMac(MySqlConnection connection, Guid source, LinkageDescriptor linkageDescriptor)
        {
            if (linkageDescriptor.IpMacNotificationLinkages == null)
                return;

            if (linkageDescriptor.IpMacNotificationLinkages.Count == 0)
                return;

            MySqlCommand mySqlCommand = connection.CreateCommand();
            mySqlCommand.CommandText =
                "INSERT INTO dvb_sdt_linkages_ipmac (uuid, id) VALUES (@uuid, @id)";
            mySqlCommand.Parameters.Add("@uuid", MySqlDbType.VarChar);
            mySqlCommand.Parameters.Add("@id", MySqlDbType.Int32);

            mySqlCommand.Parameters["@uuid"].Value = source.ToString();
            foreach (LinkageDescriptor.IpMacNotificationLinkage ipMacNotificationLinkage in linkageDescriptor.IpMacNotificationLinkages)
            {
                mySqlCommand.Parameters["@id"].Value = ipMacNotificationLinkage.Id;
                mySqlCommand.ExecuteNonQuery();

                InsertSdtLinkageIpMacNames(connection, source, ipMacNotificationLinkage);
            }
        }

        private void InsertSdtLinkageIpMacNames(MySqlConnection connection, Guid source, LinkageDescriptor.IpMacNotificationLinkage ipMacNotificationLinkage)
        {
            if (ipMacNotificationLinkage.Names == null)
                return;

            if (ipMacNotificationLinkage.Names.Count == 0)
                return;

            MySqlCommand mySqlCommand = connection.CreateCommand();
            mySqlCommand.CommandText =
                "INSERT INTO dvb_sdt_linkages_ipmac_names (uuid, id, lang, name) VALUES (@uuid, @id, @lang, @name)";
            mySqlCommand.Parameters.Add("@uuid", MySqlDbType.VarChar);
            mySqlCommand.Parameters.Add("@id", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@lang", MySqlDbType.VarChar);
            mySqlCommand.Parameters.Add("@name", MySqlDbType.VarChar);
            mySqlCommand.Parameters["@uuid"].Value = source.ToString();
            mySqlCommand.Parameters["@id"].Value = ipMacNotificationLinkage.Id;

            foreach (Tuple<string, string> tuple in ipMacNotificationLinkage.Names)
            {
                mySqlCommand.Parameters["@lang"].Value = tuple.Item1;
                mySqlCommand.Parameters["@name"].Value = tuple.Item2;
                mySqlCommand.ExecuteNonQuery();
            }
        }

        private void InsertSdtLinkageExtendedEvent(MySqlConnection connection, Guid source, LinkageDescriptor linkageDescriptor)
        {
            if (linkageDescriptor.ExtendedEventLinkages == null)
                return;

            if (linkageDescriptor.ExtendedEventLinkages.Length == 0)
                return;

            MySqlCommand mySqlCommand = connection.CreateCommand();
            mySqlCommand.CommandText =
                "INSERT INTO dvb_sdt_linkages_extended_event_linkages " +
                "    (uuid, target_event, target_listed, event_simulcast, link_type, user_defined_id, target_tsid, target_onid, target_service_id) " +
                "VALUES " +
                "    (@uuid,@target_event,@target_listed,@event_simulcast,@link_type,@user_defined_id,@target_tsid,@target_onid,@target_service_id)";
            mySqlCommand.Parameters.Add("@uuid", MySqlDbType.VarChar);
            mySqlCommand.Parameters.Add("@target_event", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@target_listed", MySqlDbType.Bool);
            mySqlCommand.Parameters.Add("@event_simulcast", MySqlDbType.Bool);
            mySqlCommand.Parameters.Add("@link_type", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@user_defined_id", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@target_tsid", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@target_onid", MySqlDbType.Int32);
            mySqlCommand.Parameters.Add("@target_service_id", MySqlDbType.Int32);

            mySqlCommand.Parameters["@uuid"].Value = source.ToString();
            foreach (LinkageDescriptor.ExtendedEventLinkageInfo eventLinkage in linkageDescriptor.ExtendedEventLinkages)
            {
                mySqlCommand.Parameters["@target_event"].Value = eventLinkage.TargetEventId;
                mySqlCommand.Parameters["@target_listed"].Value = eventLinkage.TargetListed;
                mySqlCommand.Parameters["@event_simulcast"].Value = eventLinkage.EventSimulcast;
                mySqlCommand.Parameters["@link_type"].Value = eventLinkage.LinkType;
                mySqlCommand.Parameters["@user_defined_id"].Value = eventLinkage.UserDefinedId;
                mySqlCommand.Parameters["@target_tsid"].Value = eventLinkage.TargetTransportStreamId;
                mySqlCommand.Parameters["@target_onid"].Value = eventLinkage.TargetOriginalNetworkId;
                mySqlCommand.Parameters["@target_service_id"].Value = eventLinkage.TargetServiceId;
                SetNulls(mySqlCommand);
                mySqlCommand.ExecuteNonQuery();
            }
        }

        private bool HasLinkages(ICollection<LinkageDescriptor> links)
        {
            if (links == null)
                return false;

            if (links.Count == 0)
                return false;

            return true;
        }
    }
}
