using System.Data;
using Insight.Database;
using PlanTempus.Core.Database.ConnectionFactory;
using PlanTempus.Database.Common;
using PlanTempus.Database.Core;

namespace PlanTempus.Database.Core.DCL
{
	public class SetupOrganization : IDbConfigure<SetupOrganization.Command>
    {
        public class Command
        {
            public required string Schema { get; init; }
            public required string User { get; init; }
            public required string Password { get; init; }
        }

        Command _command;
        private readonly IDbConnectionFactory _connectionFactory;


        public SetupOrganization(IDbConnectionFactory connectionFactory)
        {
            _connectionFactory = connectionFactory;
        }

        public void With(Command command, ConnectionStringParameters parameters = null)
        {
            _command = command;

            if (!Validations.IsValidSchemaName(_command.Schema))
                throw new ArgumentException("Invalid schema name", _command.Schema);

            using var conn = parameters is null ? _connectionFactory.Create() : _connectionFactory.Create(parameters);
            using var transaction = conn.OpenWithTransaction();
            try
            {
                CreateSchema(conn);
                CreateRole(conn);
                GrantSchemaRights(conn);

                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();
                throw new InvalidOperationException("Failed to SetupOrganization in Database", ex);
            }

        }
       
        private void CreateSchema(IDbConnection db)
        {
            var sql = $"CREATE SCHEMA IF NOT EXISTS {_command.Schema}";
            db.ExecuteSql(sql);
        }

        private void CreateRole(IDbConnection db)
        {
            var sql = $"CREATE ROLE {_command.User} LOGIN PASSWORD '{_command.Password}';";
            db.ExecuteSql(sql);

            var sql1 = $"ALTER ROLE {_command.User} SET search_path='{_command.Schema}';";
            db.ExecuteSql(sql1);

        }

        private void GrantSchemaRights(IDbConnection db)
        {
            var sql = $"GRANT USAGE ON SCHEMA {_command.Schema} TO {_command.User};";
            db.ExecuteSql(sql);

            var sql1 = $"ALTER DEFAULT PRIVILEGES IN SCHEMA {_command.Schema} " +
                        $"GRANT INSERT, SELECT, UPDATE PRIVILEGES ON TABLES TO {_command.User};";
            db.ExecuteSql(sql1);

            var sql2 = $"GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA {_command.Schema} TO {_command.User};";
            db.ExecuteSql(sql2);

            var sql3 = $"GRANT CREATE TABLE ON SCHEMA {_command.Schema} TO {_command.User};";
            db.ExecuteSql(sql3);
        }
        public void RevokeCreateTable(IDbConnection db)
        {
            var sql = $"REVOKE CREATE TABLE ON SCHEMA {_command.Schema} FROM {_command.User};";
            db.ExecuteSql(sql);
        }
    }
}
