using Krypton.Toolkit;
using qtcnet_client.Factories;
using qtcnet_client.Properties;
using QtCNETAPI.Models;
using QtCNETAPI.Services.ApiService;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace qtcnet_client.Forms
{
    public partial class ProfileForm : Form
    {
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string UserId { get; set; } = string.Empty;
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string Username { get; set; } = "Username";
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string Bio { get; set; } = string.Empty;
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public int Status { get; set; } = 0;
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string TextStatus { get; set; } = string.Empty;
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public string[] Tags { get; set; } = [];
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Contact.ContactStatus ContactStatus { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Image ProfileImage { get; set; } = Resources.DefaultPfp;

        public event EventHandler? OnMessageClicked;
        public event EventHandler? OnClose;

        private IApiService _apiService;
        private ImageFactory _imgFactory;
        public ProfileForm(IApiService apiService, ImageFactory imageFactory)
        {
            _apiService = apiService;
            _imgFactory = imageFactory;
            InitializeComponent();
        }

        private async void ProfileForm_Load(object sender, EventArgs e)
        {
            Text = $"QtC.NET User Profile - {Username}";
            lblUsername.Text = Username;
            lblStatus.Text = TextStatus;
            rtxtBio.Text = Bio;
            pbProfileImage.Image = ProfileImage;

            ResizeFormToUsername();

            if (Status == 0) lblStatus.Visible = false;

            if (UserId == _apiService.CurrentUser?.Id)
            {
                btnAction1.Visible = false;
                btnAction2.Visible = false;

                btnSaveProfile.Visible = true;
                rtxtBio.ReadOnly = false;

                pbProfileImage.ContextMenuStrip = ctxBoughtItems;

                // get owned store items and populate context strip
                var _storeItems = await _apiService.GetOwnedStoreItems();
                if(_storeItems.Success && _storeItems.Data != null)
                {
                    foreach(var item in _storeItems.Data)
                    {
                        // get item
                        var _item = await _apiService.GetStoreItem(item.StoreItemId);
                        if (_item.Success && _item.Data != null)
                        {
                            var tsi = ctxBoughtItems.Items.Add(_item.Data.Name, null, ProfileForm_StoreItemToolStripClick);
                            tsi.Tag = _item.Data.Id;
                        }
                    }
                }
            }

            switch (ContactStatus)
            {
                case Contact.ContactStatus.Accepted:
                    if (Status == 0) btnAction1.Visible = false;
                    btnAction1.Image = Resources.MessageIcon;
                    btnAction2.Image = Resources.RemoveContactIcon;
                    btnAction1.Click += BtnAction1_MessageClick;
                    btnAction2.Click += BtnAction2_RemoveContactClick;
                    break;
                case Contact.ContactStatus.AwaitingApprovalFromSelf:
                    btnAction1.Image = Resources.AcceptContactIcon;
                    btnAction2.Image = Resources.DeclineContactIcon;
                    btnAction1.Click += BtnAction1_AcceptContactClick;
                    btnAction2.Click += BtnAction2_DeclineContactClick;
                    break;
                case Contact.ContactStatus.AwaitingApprovalFromOther:
                    btnAction1.Image = Resources.RequestSentIcon;
                    btnAction2.Image = Resources.CancelRequestIcon;
                    btnAction1.Enabled = false;
                    btnAction2.Click += BtnAction2_CancelContactRequestClick;
                    break;
                case Contact.ContactStatus.NoRelation:
                    btnAction1.Image = null;
                    btnAction2.Image = Resources.AddContactIcon;
                    btnAction1.Enabled = false;
                    btnAction2.Click += BtnAction2_AddContactClick;
                    break;
            }
        }

        private async void ProfileForm_StoreItemToolStripClick(object? sender, EventArgs e)
        {
            if(sender is ToolStripItem _tsi && _tsi.Tag is int _itemId)
            {
                var _res = await _apiService.UpdateUserInformationAsync(new()
                {
                    Id = _apiService.CurrentUser!.Id,
                    Username = lblUsername.Text,
                    Bio = rtxtBio.Text,
                    DateOfBirth = _apiService.CurrentUser.DateOfBirth,
                    ProfileCosmeticId = _itemId,
                });
                if (_res.Success)
                    pbProfileImage.Image = _imgFactory.GetAndCreateProfileImage(UserId, Status, _itemId);
            }
        }

        private async void BtnAction2_AddContactClick(object? sender, EventArgs e)
        {
            // send request to add user as a contact
            var _res = await _apiService.AddContactToCurrentUser(UserId);
            if (_res.Success && _res.Data != null)
            {
                if (_res.Data.OwnerId == UserId)
                    ContactStatus = _res.Data.UserStatus;
                else
                    ContactStatus = _res.Data.OwnerStatus;
            }

            ReevaluateContactStatus();
        }

        private async void BtnAction2_CancelContactRequestClick(object? sender, EventArgs e)
        {
            // remove contact from user
            var _res = await _apiService.RemoveContactFromCurrentUser(UserId);
            if (_res.Success && _res.Data != null)
                ContactStatus = Contact.ContactStatus.NoRelation;

            ReevaluateContactStatus();
        }

        private async void BtnAction1_AcceptContactClick(object? sender, EventArgs e)
        {
            // accept contact request
            var _res = await _apiService.AcceptContactRequest(UserId);
            if (_res.Success)
                ContactStatus = Contact.ContactStatus.Accepted;

            ReevaluateContactStatus();
        }

        private async void BtnAction2_DeclineContactClick(object? sender, EventArgs e)
        {
            // remove contact from user
            var _res = await _apiService.RemoveContactFromCurrentUser(UserId);
            if (_res.Success && _res.Data != null)
                ContactStatus = Contact.ContactStatus.NoRelation;

            ReevaluateContactStatus();
        }

        private void BtnAction1_MessageClick(object? sender, EventArgs e)
        {
            Close();
            OnMessageClicked?.Invoke(this, EventArgs.Empty);
        }

        private async void BtnAction2_RemoveContactClick(object? sender, EventArgs e)
        {
            // remove contact from user
            var _res = await _apiService.RemoveContactFromCurrentUser(UserId);
            if (_res.Success && _res.Data != null)
                ContactStatus = Contact.ContactStatus.NoRelation;

            ReevaluateContactStatus();
        }

        private void ProfileForm_FormClosed(object sender, FormClosedEventArgs e) => OnClose?.Invoke(this, EventArgs.Empty);

        private void ReevaluateContactStatus()
        {
            if (UserId != _apiService.CurrentUser?.Id)
            {
                switch (ContactStatus)
                {
                    case Contact.ContactStatus.Accepted:
                        if (Status == 0) btnAction1.Visible = false;
                        btnAction1.Image = Resources.MessageIcon;
                        btnAction2.Image = Resources.RemoveContactIcon;
                        btnAction1.Click += BtnAction1_MessageClick;
                        btnAction2.Click += BtnAction2_RemoveContactClick;
                        break;
                    case Contact.ContactStatus.AwaitingApprovalFromSelf:
                        btnAction1.Image = Resources.AcceptContactIcon;
                        btnAction2.Image = Resources.DeclineContactIcon;
                        btnAction1.Click += BtnAction1_AcceptContactClick;
                        btnAction2.Click += BtnAction2_DeclineContactClick;
                        break;
                    case Contact.ContactStatus.AwaitingApprovalFromOther:
                        btnAction1.Image = Resources.RequestSentIcon;
                        btnAction2.Image = Resources.CancelRequestIcon;
                        btnAction1.Enabled = false;
                        btnAction2.Click += BtnAction2_CancelContactRequestClick;
                        break;
                    case Contact.ContactStatus.NoRelation:
                        btnAction1.Image = null;
                        btnAction2.Image = Resources.AddContactIcon;
                        btnAction1.Enabled = false;
                        btnAction2.Click += BtnAction2_AddContactClick;
                        break;
                }
            }
            else
            {
                btnAction1.Enabled = false;
                btnAction2.Enabled = false;
            }
        }

        private void lblUsername_DoubleClick(object sender, EventArgs e)
        {
            if (UserId == _apiService.CurrentUser?.Id)
            {
                lblUsername.Visible = false;

                TextBox txtUsernameEdit = new()
                {
                    Text = lblUsername.Text,
                    Font = lblUsername.Font,
                    MaxLength = 25,
                    Dock = lblUsername.Dock,
                    Location = lblUsername.Location,
                    Size = lblUsername.Size,
                };
                txtUsernameEdit.KeyDown += TxtUsernameEdit_KeyDown;
                tlpUsernameTags.Controls.Add(txtUsernameEdit);
                txtUsernameEdit.Focus();
            }
        }

        private void TxtUsernameEdit_KeyDown(object? sender, KeyEventArgs e)
        {
            if (sender is TextBox txtUsernameEdit && e.KeyCode == Keys.Enter)
            {
                lblUsername.Text = txtUsernameEdit.Text;
                tlpUsernameTags.Controls.Remove(txtUsernameEdit);
                txtUsernameEdit.Dispose();
                ResizeFormToUsername();
                lblUsername.Visible = true;
            }
        }

        private async void btnSaveProfile_Click(object sender, EventArgs e)
        {
            // update current user profile based on stuff inputted
            var _res = await _apiService.UpdateUserInformationAsync(new()
            {
                Id = _apiService.CurrentUser!.Id,
                Username = lblUsername.Text,
                Bio = rtxtBio.Text,
                DateOfBirth = _apiService.CurrentUser.DateOfBirth,
            });
            if (_res.Success && _res.Data != null)
                KryptonMessageBox.Show("Profile Updated", "Yipee!");
            else
                KryptonMessageBox.Show("Profile Update Failed. Please Try Again Later.", "Oops.");
        }

        private void pbProfileImage_Click(object sender, MouseEventArgs e)
        {
            if(UserId == _apiService.CurrentUser?.Id)
            {
                Thread _fileDialogThread = new Thread(async () =>
                {
                    using OpenFileDialog openFileDialog = new()
                    {
                        CheckFileExists = true,
                        CheckPathExists = true,
                        InitialDirectory = Environment.CurrentDirectory,
                        Filter = "Image Files (*.png, *.jpg, *.gif, *.bmp)|*.png;*.jpg;*.gif;*.bmp",
                        Title = "Select A New Profile Image"
                    };
                    var _res = openFileDialog.ShowDialog();
                    if(_res == DialogResult.OK)
                    {
                        // update the current users profile image
                        var _apiRes = await _apiService.UpdateUserProfilePic(openFileDialog.FileName);
                        if(_apiRes.Success)
                        {
                            Image newImg = Image.FromFile(openFileDialog.FileName);
                            pbProfileImage.Image = newImg;
                            pbProfileImage.Invalidate();
                        }
                    }
                });

                _fileDialogThread.SetApartmentState(ApartmentState.STA);
                _fileDialogThread.Start();
            }
        }

        private void pbProfileImage_MouseEnter(object sender, EventArgs e)
        {
            if(UserId == _apiService.CurrentUser?.Id)
            {
                Graphics g = pbProfileImage.CreateGraphics();
                Rectangle rect = pbProfileImage.ClientRectangle;

                // draw an opaque dark color onto the client rectangle of the picturebox
                using SolidBrush sb = new(Color.FromArgb(50, Color.Black));
                g.FillRectangle(sb, rect);

                pbProfileImage.Cursor = Cursors.Hand;
            }
        }

        private void pbProfileImage_MouseLeave(object sender, EventArgs e)
        {
            // redraw the box normally
            pbProfileImage.Cursor = Cursors.Default;
            pbProfileImage.Invalidate();
        }

        private void ResizeFormToUsername()
        {
            int padding = 40;
            int minWidth = 445;
            int newWidth = lblUsername.Right + padding;

            if (newWidth > minWidth)
                Width = newWidth;
        }
    }
}
