using System;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using Npgsql;

namespace ProviderApp
{
    public static class AuthHelper
    {
        public static class CurrentUser
        {
            public static int Id { get; set; }
            public static string Username { get; set; }
            public static string FullName { get; set; }
            public static string Role { get; set; }
            public static bool IsAuthenticated { get; set; }
            public static bool IsAdmin => Role == "admin";
            public static bool IsManager => Role == "manager" || Role == "admin";
        }

        public static string HashMD5(string input)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] inputBytes = Encoding.UTF8.GetBytes(input);
                byte[] hashBytes = md5.ComputeHash(inputBytes);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                    sb.Append(hashBytes[i].ToString("x2"));
                return sb.ToString();
            }
        }

        public static bool Login(string username, string password)
        {
            try
            {
                string passwordHash = HashMD5(password);
                using (var conn = DBConnection.GetConnection())
                {
                    string sql = @"
                        SELECT u.user_id, u.username, u.full_name, r.role_name 
                        FROM users u
                        JOIN roles r ON u.role_id = r.role_id
                        WHERE u.username = @username AND u.password_hash = @password AND u.is_active = true";

                    using (var cmd = new NpgsqlCommand(sql, conn))
                    {
                        cmd.Parameters.AddWithValue("@username", username);
                        cmd.Parameters.AddWithValue("@password", passwordHash);

                        using (var reader = cmd.ExecuteReader())
                        {
                            if (reader.Read())
                            {
                                CurrentUser.Id = reader.GetInt32(0);
                                CurrentUser.Username = reader.GetString(1);
                                CurrentUser.FullName = reader.IsDBNull(2) ? username : reader.GetString(2);
                                CurrentUser.Role = reader.GetString(3);
                                CurrentUser.IsAuthenticated = true;

                                LogAction("Вход в систему", "users", CurrentUser.Id);
                                return true;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Ошибка входа: {ex.Message}");
            }
            return false;
        }

        public static void Logout()
        {
            if (CurrentUser.IsAuthenticated)
            {
                LogAction("Выход из системы", "users", CurrentUser.Id);
                CurrentUser.IsAuthenticated = false;
                CurrentUser.Id = 0;
                CurrentUser.Username = "";
                CurrentUser.FullName = "";
                CurrentUser.Role = "";
            }
        }

        public static void LogAction(string action, string tableName, int recordId = 0)
        {
            if (!CurrentUser.IsAuthenticated) return;

            try
            {
                using (var conn = DBConnection.GetConnection())
                {
                    string sql = @"INSERT INTO user_logs (user_id, action, table_name, record_id) 
                                  VALUES (@user_id, @action, @table_name, @record_id)";
                    using (var cmd = new NpgsqlCommand(sql, conn))
                    {
                        cmd.Parameters.AddWithValue("@user_id", CurrentUser.Id);
                        cmd.Parameters.AddWithValue("@action", action);
                        cmd.Parameters.AddWithValue("@table_name", tableName);
                        cmd.Parameters.AddWithValue("@record_id", recordId);
                        cmd.ExecuteNonQuery();
                    }
                }
            }
            catch { }
        }

        public static bool CheckPermission(string requiredRole)
        {
            if (!CurrentUser.IsAuthenticated)
            {
                MessageBox.Show("Требуется авторизация!", "Доступ запрещён",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return false;
            }

            if (requiredRole == "admin" && !CurrentUser.IsAdmin)
            {
                MessageBox.Show("Доступ только для администратора!", "Доступ запрещён",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return false;
            }

            if (requiredRole == "manager" && !CurrentUser.IsManager)
            {
                MessageBox.Show("Доступ только для менеджеров!", "Доступ запрещён",
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return false;
            }

            return true;
        }

        public static string MaskSensitiveData(string data)
        {
            if (string.IsNullOrEmpty(data) || data.Length < 3)
                return "***";

            // Для администратора и менеджера показываем всё
            if (CurrentUser.IsAdmin || CurrentUser.IsManager)
                return data;

            // Маскирование паспорта (серия и номер)
            if (data.Length == 10 && (data.Contains(" ") || (char.IsDigit(data[0]) && char.IsDigit(data[1]))))
            {
                string cleanData = data.Replace(" ", "");
                if (cleanData.Length == 10)
                {
                    return "**** " + cleanData.Substring(cleanData.Length - 4);
                }
                return "**** ****";
            }

            // Маскирование ИНН (10 или 12 цифр)
            if (data.Length == 10 || data.Length == 12)
            {
                bool isAllDigits = true;
                foreach (char c in data)
                {
                    if (!char.IsDigit(c))
                    {
                        isAllDigits = false;
                        break;
                    }
                }
                if (isAllDigits)
                {
                    return "***" + data.Substring(data.Length - 3);
                }
            }

            // Маскирование СНИЛС (11 цифр, формат XXX-XXX-XXX XX)
            string cleanSnils = data.Replace("-", "").Replace(" ", "");
            if (cleanSnils.Length == 11)
            {
                bool isAllDigits = true;
                foreach (char c in cleanSnils)
                {
                    if (!char.IsDigit(c))
                    {
                        isAllDigits = false;
                        break;
                    }
                }
                if (isAllDigits)
                {
                    return "***-***-" + cleanSnils.Substring(cleanSnils.Length - 3);
                }
            }

            // Маскирование телефона (11 цифр)
            string cleanPhone = data.Replace("+", "").Replace("-", "").Replace("(", "").Replace(")", "").Replace(" ", "");
            if (cleanPhone.Length == 11)
            {
                bool isAllDigits = true;
                foreach (char c in cleanPhone)
                {
                    if (!char.IsDigit(c))
                    {
                        isAllDigits = false;
                        break;
                    }
                }
                if (isAllDigits)
                {
                    return cleanPhone.Substring(0, 2) + "*****" + cleanPhone.Substring(7);
                }
            }

            // Маскирование email
            if (data.Contains("@"))
            {
                int atIndex = data.IndexOf('@');
                if (atIndex > 0)
                {
                    string localPart = data.Substring(0, atIndex);
                    string domain = data.Substring(atIndex);
                    if (localPart.Length <= 2)
                    {
                        return "***" + domain;
                    }
                    return localPart.Substring(0, 2) + "***" + domain;
                }
            }

            // Маскирование адреса
            if (data.Length > 6)
            {
                return data.Substring(0, 3) + "***" + data.Substring(data.Length - 3);
            }

            // Общее маскирование
            if (data.Length <= 4)
            {
                return "***";
            }

            return data.Substring(0, 2) + "***" + data.Substring(data.Length - 2);
        }

        public static string MaskPassport(string series, string number)
        {
            if (string.IsNullOrEmpty(series) || string.IsNullOrEmpty(number))
                return "***";

            if (CurrentUser.IsAdmin || CurrentUser.IsManager)
                return $"{series} {number}";

            return $"**** {number.Substring(Math.Max(0, number.Length - 4))}";
        }

        public static string GetMaskedPassportFromDb(int clientId)
        {
            try
            {
                using (var conn = DBConnection.GetConnection())
                {
                    string sql = "SELECT passport_series, passport_number FROM clients WHERE client_id = @id";
                    using (var cmd = new NpgsqlCommand(sql, conn))
                    {
                        cmd.Parameters.AddWithValue("@id", clientId);
                        using (var reader = cmd.ExecuteReader())
                        {
                            if (reader.Read())
                            {
                                string series = reader["passport_series"]?.ToString();
                                string number = reader["passport_number"]?.ToString();
                                return MaskPassport(series, number);
                            }
                        }
                    }
                }
            }
            catch { }
            return "***";
        }
    }
}