using boilerplate.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data.Entity;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web;
using System.Web.Hosting;
using System.Web.Http;

namespace boilerplate.Controllers
{
    public class UserController : ApiController
    {
        readonly boilerplateEntities db = new boilerplateEntities();
        SmsManagment Sms = new SmsManagment();
        readonly Functions functions = new Functions();


        [Route("api/User/Manage")]
        [HttpPost]
        public async Task<StatusModel> Manage()
        {
            StatusModel statusModel = new StatusModel() { Status = "Success" };
            try
            {
                if (Request.Content.IsMimeMultipartContent())
                {
                    var Provider = await Request.Content.ReadAsMultipartAsync(new InMemoryMultipartFormDataStreamProvider());
                    NameValueCollection FormData = Provider.FormData;
                    if (string.IsNullOrEmpty(FormData.Get("Model"))) { statusModel.Status = "Empty"; }
                    else
                    {
                        var model = JsonConvert.DeserializeObject<UserModel>(FormData.Get("Model"));
                        var userAccessModel = functions.CheckUserAccess(model.Auth, new string[] { "Admin" }, new string[] { "All", "ManageUser" });

                        if (userAccessModel.Id != 0)
                        {
                            string FileName = string.Empty;
                            DateTime Now = DateTime.Now;
                            List<HttpContent> Files = Provider.Files;
                            #region
                            if (Files.Count > 0)
                            {
                                HttpContent UploadedFile = Files[0];
                                Stream UploadedFileReader = await UploadedFile.ReadAsStreamAsync();
                                string OrginalFileName = UploadedFile.Headers.ContentDisposition.FileName.Trim('\"');
                                var Limit = 3145728; // 3 megabyte
                                if (UploadedFileReader.Length > Limit)
                                {
                                    statusModel.Status = "Limit";
                                    statusModel.Message = $"{Limit}";
                                    return statusModel;
                                }
                                if (!MimeMapping.GetMimeMapping(OrginalFileName).StartsWith("image/"))
                                {
                                    statusModel.Status = "Format";
                                    return statusModel;
                                }
                                PersianCalendar pc = new PersianCalendar();
                                string CurrentDate = $"{pc.GetYear(Now)}_{pc.GetMonth(Now)}_{pc.GetDayOfMonth(Now)}_{pc.GetHour(Now)}_{pc.GetMinute(Now)}_{pc.GetSecond(Now)}_{pc.GetMilliseconds(Now)}_{new Random().Next(10000, 99999)}";
                                FileName = CurrentDate + Path.GetExtension(OrginalFileName);
                                string FullPath = HostingEnvironment.MapPath($"~/Media/User/");
                                using (Stream UploadedFileWriter = File.OpenWrite(Path.Combine(FullPath, FileName)))
                                {
                                    await UploadedFileReader.CopyToAsync(UploadedFileWriter);
                                    UploadedFileWriter.Close();
                                }
                            }
                            #endregion
                            if (model.Id == 0)
                            {
                                var Single = new User()
                                {
                                    User_Name = model.Name,
                                    User_Family = model.Family,
                                    User_Image = string.IsNullOrEmpty(FileName) ? "dUser.png" : FileName,
                                    User_Phone = model.Phone,
                                    User_Password = functions.HashPassword(model.Password + Now),
                                    User_NationalCode = model.NationalCode,
                                    User_Status = model.Status,
                                    User_Role = model.Role,
                                    User_Access = model.Access,
                                    User_Token = null,
                                    User_Code = null,
                                    User_CreatedDate = Now,
                                    User_CreatedDateFa = functions.ConvertToPersianDate(Now),
                                    User_LoginDate = null,
                                    User_LoginDateFa = null,
                                };
                                db.Users.Add(Single);
                                await db.SaveChangesAsync();
                                statusModel.Result = $"{Single.User_Id}";
                            }
                            else
                            {
                                var Single = await db.Users.FindAsync(model.Id);
                                if (Single != null)
                                {
                                    Single.User_Name = model.Name;
                                    Single.User_Family = model.Family;
                                    if (!string.IsNullOrEmpty(FileName)) { Single.User_Image = FileName; }
                                    Single.User_Phone = model.Phone;
                                    if (!string.IsNullOrEmpty(model.Password)) { Single.User_Password = functions.HashPassword(model.Password + Single.User_CreatedDate); }
                                    Single.User_NationalCode = model.NationalCode;
                                    Single.User_Status = model.Status;
                                    Single.User_Role = model.Role;
                                    Single.User_Access = model.Access;
                                    await db.SaveChangesAsync();
                                    statusModel.Result = $"{Single.User_Id}";


                                    //sms
                                    if (model.Status == 1 && !string.IsNullOrEmpty(model.Password) && Single.User_Role == "User")
                                    {
                                        string[] phone = { Single.User_Phone };
                                        string SmsPaternLogin = functions.ReadSetting("RegisterConfirmation");
                                        if (!string.IsNullOrEmpty(SmsPaternLogin))
                                        {
                                            new SmsManagment().SendSms(new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("userName", $"{Single.User_Phone}"), new KeyValuePair<string, string>("password", model.Password) }, phone, SmsPaternLogin);
                                        }
                                    }
                                }
                                else { statusModel.Status = "NotFound"; }
                            }
                        }
                        else { statusModel.Status = "Auth"; }
                    }
                }
                else { statusModel.Status = "NotData"; }
            }
            catch (Exception ex) { statusModel.Status = "Error"; statusModel.Result = ex.Message; }
            return statusModel;
        }

        [Route("api/User/Counters")]
        [HttpGet]
        public List<int> Counters()
        {
            var counterList = new List<int>(new int[] { 0, 0, 0, 0, 0, 0 });

            try
            {
                // Assuming db is your database context
                var users = db.Users
                    .Select(c => new { c.User_Status, c.User_Role })
                    .ToList();

                foreach (var user in users)
                {
                    int userStatus = user.User_Status; // Assuming Customer_Status is nullable
                    int userRole = user.User_Role == "Hr" ? 4 : 5;

                    counterList[0]++; // Total count
                    counterList[userStatus + 1]++; // Status-based count
                    counterList[userRole]++; // Role-based count
                }
            }
            catch
            {
                // Handle exceptions as needed
            }

            return counterList;
        }

        [Route("api/User/Login")]
        [HttpPost]
        public async Task<HttpResponseMessage> Login([FromBody] PhoneModel model)
        {
            try
            {
                if (string.IsNullOrEmpty(model.Phone))
                {
                    return Request.CreateResponse(HttpStatusCode.OK, new { Status = "Empty" });
                }
                else if (model.Phone.Length != 11)
                {
                    return Request.CreateResponse(HttpStatusCode.OK, new { Status = "Length" });
                }
                else if (model.Phone.Substring(0, 2) != "09")
                {
                    return Request.CreateResponse(HttpStatusCode.OK, new { Status = "Format" });
                }

                DateTime nowTime = DateTime.Now;
                string code = new Random().Next(10000, 99999).ToString();
                int status;
                int id;

                var user = db.Users.SingleOrDefault(u => u.User_Phone == model.Phone);

                if (user != null)
                {
                    // Existing user
                    id = user.User_Id;
                    status = user.User_Status;

                    // Generate token
                    byte[] time = BitConverter.GetBytes(nowTime.ToBinary());
                    byte[] key = Guid.NewGuid().ToByteArray();
                    string token = Convert.ToBase64String(time.Concat(key).ToArray());

                    // Update user with new password and token
                    user.User_Code = Convert.ToInt32(code);
                    user.User_Token = token;
                    user.User_LoginDate = nowTime;
                    user.User_LoginDateFa = functions.ConvertToPersianDate(nowTime);
                  

                    db.SaveChanges();

                    string[] phone = { user.User_Phone };
                    string SmsPaternLogin = functions.ReadSetting("SmsPaternLogin");
                    if (!string.IsNullOrEmpty(SmsPaternLogin))
                    {
                        new SmsManagment().SendSms(new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("verification-code", $"{code}") }, phone, SmsPaternLogin);
                    }

                    return Request.CreateResponse(HttpStatusCode.OK, new { Status = "OK" });
                }
                else
                {

                    return Request.CreateResponse(HttpStatusCode.OK, new { Status = "NoExist" });
                }
            }
            catch (Exception e)
            {
                return Request.CreateResponse(HttpStatusCode.OK, new { Status = e.Message });
            }
        }

        [Route("api/User/CheckCode")]
        [HttpPost]
        public async Task<HttpResponseMessage> CheckCodeAsync([FromBody] CheckCodeModel model)
        {
            try
            {
                if (string.IsNullOrEmpty(model.Phone) || string.IsNullOrEmpty(model.Code))
                {
                    return Request.CreateResponse(HttpStatusCode.OK, new { Status = "Empty" });
                }
                int code = Convert.ToInt32(model.Code);
                // Query the user based on Phone and Code
                var user = db.Users
                    .FirstOrDefault(u => u.User_Phone == model.Phone && u.User_Code == code && u.User_Status != 0);

                if (user != null)
                {
                    // If the user is found, generate a new token
                    DateTime now = DateTime.Now;
                    byte[] time = BitConverter.GetBytes(now.ToBinary());
                    byte[] key = Guid.NewGuid().ToByteArray();
                    string Token = Convert.ToBase64String(time.Concat(key).ToArray());

                    // Update the user's token, clear password, and change status
                    user.User_Token = Token;
                    user.User_Code = null;
                    user.User_Status = 1; // Assuming 1 represents an active status
                    user.User_LoginDate = now;
                    user.User_LoginDateFa = functions.ConvertToPersianDate(now); // Assuming DateModifiedGmt is the same but in UTC

                    db.SaveChanges();

                    return Request.CreateResponse(HttpStatusCode.OK, new
                    {
                        Status = "Success",
                        Token = Token,
                        Id = user.User_Id,
                        Phone = user.User_Phone,
                    });
                }
                else
                {
                    return Request.CreateResponse(HttpStatusCode.OK, new { Status = "Wrong" });
                }
            }
            catch (Exception)
            {
                return Request.CreateResponse(HttpStatusCode.OK, new { Status = "Error", Type = "" });
            }
        }

        [Route("api/User/Delete")]
        [HttpPost]
        public async Task<StatusModel> Delete(AuthModel model)
        {
            StatusModel statusModel = new StatusModel() { Status = "Success" };
            try
            {
                if (model.Id != 0)
                {
                    var userAccessModel = functions.CheckUserAccess(model, new string[] { "Admin" }, new string[] { "All", $"ManageUser" });
                    if (userAccessModel.Id != 0)
                    {
                        var Single = await db.Users.FindAsync(model.Id);
                        if (Single != null)
                        {
                            db.Users.Remove(Single);
                            await db.SaveChangesAsync();
                        }
                        else { statusModel.Status = "NotFound"; }
                    }
                    else { statusModel.Status = "Auth"; }
                }
                else { statusModel.Status = "Empty"; }
            }
            catch (Exception ex)
            {
                statusModel.Status = "Error";
                statusModel.Message = ex.Message;
            }
            return statusModel;
        }
    }
}