using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

using Plus.HabboHotel.GameClients;
using Plus.HabboHotel.Rooms;
using Plus.HabboHotel.Users;
using Plus.Communication.Packets.Incoming;
using System.Collections.Concurrent;

using Plus.Database.Interfaces;
using log4net;
using Plus.Core;
using Plus.Utilities;

namespace Plus.HabboHotel.Groups
{
    public class GroupManager
    {
        private static readonly ILog log = LogManager.GetLogger("Plus.HabboHotel.Groups.GroupManager");

        public Dictionary<int, GroupBackGroundColours> BackGroundColours;
        public List<GroupBaseColours> BaseColours;
        public List<GroupBases> Bases;

        public Dictionary<int, GroupSymbolColours> SymbolColours;
        public List<GroupSymbols> Symbols;

        private readonly Object _groupLoadingSync;
        private ConcurrentDictionary<int, Group> _groups;

        public GroupManager()
        {
            this._groupLoadingSync = new Object();

            this.Init();
        }

        public bool TryGetGroup(int Id, out Group Group)
        {
            Group = null;

            if (this._groups.ContainsKey(Id))
                return this._groups.TryGetValue(Id, out Group);

            lock (this._groupLoadingSync)
            {
                if (this._groups.ContainsKey(Id))
                    return this._groups.TryGetValue(Id, out Group);

                DataRow Row = null;
                using (IQueryAdapter adap = PlusEnvironment.GetDatabaseManager().GetQueryReactor())
                {
                    adap.SetQuery("SELECT * FROM `groups` WHERE `id` = @id LIMIT 1");
                    adap.AddParameter("id", Id);
                    Row = adap.getRow();

                    if (Row != null)
                    {
                        Group = new Group(
                             Convert.ToInt32(Row["id"]), Convert.ToString(Row["name"]), Convert.ToString(Row["desc"]), Convert.ToString(Row["badge"]), Convert.ToInt32(Row["room_id"]), Convert.ToInt32(Row["owner_id"]),
                             Convert.ToInt32(Row["created"]), Convert.ToInt32(Row["state"]), Convert.ToInt32(Row["colour1"]), Convert.ToInt32(Row["colour2"]), Convert.ToInt32(Row["admindeco"]), Convert.ToInt32(Row["has_forum"]) == 1);
                        this._groups.TryAdd(Group.Id, Group);
                        return true;
                    }
                }
            }
            return false;
        }

        public void Init()
        {
            Bases = new List<GroupBases>();
            Symbols = new List<GroupSymbols>();
            BaseColours = new List<GroupBaseColours>();
            SymbolColours = new Dictionary<int, GroupSymbolColours>();
            BackGroundColours = new Dictionary<int, GroupBackGroundColours>();
            _groups = new ConcurrentDictionary<int, Group>();

            ClearInfo();
            using (IQueryAdapter adap = PlusEnvironment.GetDatabaseManager().GetQueryReactor())
            {
                adap.SetQuery("SELECT * FROM groups_items WHERE enabled='1'");
                DataTable dItems = adap.getTable();

                foreach (DataRow dRow in dItems.Rows)
                {
                    switch (dRow[0].ToString())
                    {
                        case "base":
                            Bases.Add(new GroupBases(Convert.ToInt32(dRow[1]), dRow[2].ToString(), dRow[3].ToString()));
                            break;

                        case "symbol":
                            Symbols.Add(new GroupSymbols(Convert.ToInt32(dRow[1]), dRow[2].ToString(), dRow[3].ToString()));
                            break;

                        case "color":
                            BaseColours.Add(new GroupBaseColours(Convert.ToInt32(dRow[1]), dRow[2].ToString()));
                            break;

                        case "color2":
                            SymbolColours.Add(Convert.ToInt32(dRow[1]), new GroupSymbolColours(Convert.ToInt32(dRow[1]), dRow[2].ToString()));
                            break;

                        case "color3":
                            BackGroundColours.Add(Convert.ToInt32(dRow[1]), new GroupBackGroundColours(Convert.ToInt32(dRow[1]), dRow[2].ToString()));
                            break;
                    }
                }
            }

            log.Info("Gestionnaire de Groupe -> [OK]");
        }

        public void ClearInfo()
        {
            Bases.Clear();
            Symbols.Clear();
            BaseColours.Clear();
            SymbolColours.Clear();
            BackGroundColours.Clear();
        }

        public bool TryCreateGroup(Habbo Player, string Name, string Description, int RoomId, string Badge, int Colour1, int Colour2, bool HasForum, uint forumMessagesCount, double forumScore, uint forumLastPosterId,
           string forumLastPosterName, int forumLastPosterTimestamp, out int groupId)
        {

            groupId = 0;

            if (string.IsNullOrWhiteSpace(Name) || string.IsNullOrWhiteSpace(Badge))
                return false;

            using (IQueryAdapter adap = PlusEnvironment.GetDatabaseManager().GetQueryReactor())
            {
                adap.SetQuery("INSERT INTO `groups` (`name`, `desc`, `badge`, `owner_id`, `created`, `room_id`, `state`, `colour1`, `colour2`, `admindeco`) VALUES (@name, @desc, @badge, @owner, UNIX_TIMESTAMP(), @room, '0', @colour1, @colour2, '0')");
                adap.AddParameter("name", Name);
                adap.AddParameter("desc", Description);
                adap.AddParameter("owner", Player.Id);
                adap.AddParameter("badge", Badge);
                adap.AddParameter("room", RoomId);
                adap.AddParameter("colour1", Colour1);
                adap.AddParameter("colour2", Colour2);
                var Id = Convert.ToInt32(adap.InsertQuery());
                adap.RunQuery(string.Format("INSERT INTO group_memberships (id, group_id, user_id, rank) VALUES (NULL, '{0}','{1}','2')", Id, Player.Id));

                adap.SetQuery("UPDATE `rooms` SET `group_id` = @gid WHERE `id` = @rid LIMIT 1");
                adap.AddParameter("gid", Id);
                adap.AddParameter("rid", RoomId);
                adap.RunQuery();
                groupId = Id;
            }
            return true;
        }


        public string CheckActiveSymbol(string Symbol)
        {
            if (Symbol == "s000" || Symbol == "s00000")
            {
                return "";
            }
            return Symbol;
        }

        public string GetGroupColour(int Index, bool Colour1)
        {
            if (Colour1)
            {
                if (SymbolColours.ContainsKey(Index))
                {
                    return SymbolColours[Index].Colour;
                }
            }
            else
            {
                if (BackGroundColours.ContainsKey(Index))
                {
                    return BackGroundColours[Index].Colour;
                }
            }

            return "4f8a00";
        }

        public int GetMessageCountForThread(uint id)
        {
            using (var queryReactor = PlusEnvironment.GetDatabaseManager().GetQueryReactor())
            {
                queryReactor.SetQuery(string.Format("SELECT COUNT(*) FROM groups_forums_posts WHERE parent_id='{0}'", id));
                return int.Parse(queryReactor.getString());
            }
        }

        public void DeleteGroup(Group Group)
        {
            using (IQueryAdapter queryReactor = PlusEnvironment.GetDatabaseManager().GetQueryReactor())
            {
                queryReactor.RunQuery("DELETE FROM `groups` WHERE `id` = '" + Group.Id + "'");
                queryReactor.RunQuery("DELETE FROM `group_memberships` WHERE `group_id` = '" + Group.Id + "'");
                queryReactor.RunQuery("DELETE FROM `group_requests` WHERE `group_id` = '" + Group.Id + "'");
                queryReactor.RunQuery("UPDATE `rooms` SET `group_id` = '0' WHERE `group_id` = '" + Group.Id + "' LIMIT 1");
                queryReactor.RunQuery("UPDATE `user_stats` SET `groupid` = '0' WHERE `groupid` = '" + Group.Id + "' LIMIT 1");
            }
            Group group;
            this._groups.TryRemove(Group.Id, out group);
            if (Group == null)
                return;
            Group.Dispose();
        }


        public List<Group> GetGroupsForUser(int UserId, bool IsOwner = false)
        {
            List<Group> Groups = new List<Group>();
            using (IQueryAdapter queryReactor = PlusEnvironment.GetDatabaseManager().GetQueryReactor())
            {
                queryReactor.SetQuery("SELECT g.id FROM `group_memberships` AS m RIGHT JOIN `groups` AS g ON m.group_id = g.id WHERE m.user_id = @user");
                queryReactor.AddParameter("user", UserId);
                DataTable table = queryReactor.getTable();
                if (table != null)
                {
                    foreach (DataRow row in (InternalDataCollectionBase)table.Rows)
                    {
                        Group Group = (Group)null;
                        if (this.TryGetGroup(Convert.ToInt32(row["id"]), out Group) && (IsOwner && Group.CreatorId == UserId || !IsOwner))
                            Groups.Add(Group);
                    }
                }
            }
            return Groups;
        }
    }
}