﻿using Sleeper.Model;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading.Tasks;

namespace Sleeper.SqlServer.Utilities
{
    internal class ServiceHelper
    {
        private SqlConnection connection;

        public ServiceHelper(SqlConnection connection)
        {
            this.connection = connection;
        }

        public async Task CreateServiceAsync<TService>() where TService : Service, new()
        {
            await CreateServiceAsync(Service.Instance<TService>());
        }

        public async Task CreateServiceAsync(Service service)
        {
            var contracts = string.Join(", ", service.Contracts.Select(c => c.Name.Escaped()));

            if (!string.IsNullOrEmpty(contracts))
            {
                contracts = $"({contracts})";
            }

            var sql = $@"
IF NOT EXISTS (SELECT 1 FROM sys.services s WHERE s.name = @name)
BEGIN
    CREATE SERVICE {service.Name.Escaped()}
        ON QUEUE {service.Queue.Name.Escaped()}
        {contracts}
END
";

            var command = new SqlCommand(sql, connection)
            {
                Parameters =
                {
                    new SqlParameter
                    {
                        ParameterName = "@name",
                        Value = service.Name.Value,
                        SqlDbType = SqlDbType.NVarChar,
                        Size = 128,
                    },
                }
            };

            await command.ExecuteNonQueryAsync();
        }
        
        public async Task DropServiceAsync<TService>() where TService : Service, new()
        {
            await DropServiceAsync(Service.Instance<TService>());
        }

        public async Task DropServiceAsync(Service service)
        {
            var sql = $@"
IF EXISTS (SELECT 1 FROM sys.services s WHERE s.name = @name)
BEGIN
    DROP SERVICE {service.Name.Escaped()}
END";

            var command = new SqlCommand(sql, connection)
            {
                Parameters =
                {
                    new SqlParameter
                    {
                        ParameterName = "@name",
                        Value = service.Name.Value,
                        SqlDbType = SqlDbType.NVarChar,
                        Size = 128,
                    },
                }
            };

            await command.ExecuteNonQueryAsync();
        }
        
        public async Task<bool> ServiceExistsAsync<TService>() where TService : Service, new()
        {
            return await ServiceExistsAsync(Service.Instance<TService>());
        }

        public async Task<bool> ServiceExistsAsync(Service service)
        {
            var sql = @"SELECT CAST(1 AS bit) FROM sys.services s WHERE s.name = @name";

            var command = new SqlCommand(sql, connection)
            {
                Parameters =
                {
                    new SqlParameter
                    {
                        ParameterName = "@name",
                        Value = service.Name.Value,
                        SqlDbType = SqlDbType.NVarChar,
                        Size = 128,
                    },
                }
            };

            var result = await command.ExecuteScalarAsync();

            return (bool)result;
        }
    }
}