using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

using Microsoft.AspNetCore.Authorization;
using rockfishCore.Models;
using rockfishCore.Util;

namespace rockfishCore.Controllers
{
    [Produces("application/json")]
    [Route("api/Customer")]
    [Authorize]
    public class CustomerController : Controller
    {
        private readonly rockfishContext _context;

        public CustomerController(rockfishContext context)
        {
            _context = context;
        }

        //Get api/customer/list
        [HttpGet("list")]
        public IEnumerable<dtoCustomerListItem> GetList()
        {

            var res = from c in _context.Customer.OrderBy(c => c.Name)
                      select new dtoCustomerListItem
                      {
                          lapsed = false,
                          active = c.Active,
                          id = c.Id,
                          name = c.Name
                      };

            //Need to be made into a list before updating or else the changes would be lost
            //The tolist is what triggers the actual query to run
            var LapsedRes = res.ToList();
            foreach (dtoCustomerListItem i in LapsedRes)
            {
                i.lapsed = CustomerHasLapsed(i.id);
            }

            return LapsedRes;
        }


        /// <summary>
        /// Check if a customer has any active subs
        /// return true if no active subs
        /// Active means cancel date is empty or not yet come to pass
        /// and expire date is not empty and not yet come to pass
        /// </summary>
        /// <param name="customerId"></param>
        /// <returns></returns>
        private bool CustomerHasLapsed(long customerId)
        {
            long EpochNow = DateUtil.NowAsEpoch();

            var count = _context.Purchase
                        .Where(c => c.CustomerId.Equals(customerId))
                        .Where(c => c.CancelDate == null || c.CancelDate > EpochNow)
                        .Where(c => c.ExpireDate != null && c.ExpireDate > EpochNow)
                        .Count();

            return count < 1;

        }

        //Get api/customer/77/sitelist
        [HttpGet("{id}/sitelist")]
        public IEnumerable<dtoNameIdItem> GetSiteList([FromRoute] long id)
        {

            var res = from c in _context.Site
            .Where(c => c.CustomerId.Equals(id)).OrderBy(c => c.Name)
                      select new dtoNameIdItem
                      {
                          id = c.Id,
                          name = c.Name
                      };
            return res.ToList();
        }


        //Get api/customer/77/activesubbysite
        [HttpGet("{id}/activesubforsites")]
        public IEnumerable<dtoNameIdChildrenItem> GetActiveSubsForSites([FromRoute] long id)
        {

            var res = from c in _context.Site
                      .Where(c => c.CustomerId.Equals(id)).OrderBy(c => c.Name)
                      select new dtoNameIdChildrenItem
                      {
                          id = c.Id,
                          name = c.Name
                      };

            //Force immediate query execution
            var resList = res.ToList();

            foreach (dtoNameIdChildrenItem child in resList)
            {
                var subs = from c in _context.Purchase
                          .Where(c => c.SiteId.Equals(child.id))
                          .Where(c => c.CancelDate == null)
                          .OrderByDescending(c => c.PurchaseDate)
                           select new dtoNameIdItem
                           {
                               id = c.Id,
                               name = c.Name + " exp: " + DateUtil.EpochToString(c.ExpireDate, "d")
                           };

                foreach (dtoNameIdItem sub in subs)
                {
                    child.children.Add(sub);
                }
            }

            return resList;
        }



        //Get api/customer/77/sites
        [HttpGet("{id}/sites")]
        public IEnumerable<Site> GetSites([FromRoute] long id)
        {
            //from https://docs.microsoft.com/en-us/ef/core/querying/basic
            var sites = _context.Site
                 .Where(b => b.CustomerId.Equals(id))
                 .OrderByDescending(b => b.Id)
                 .ToList();
            return sites;
        }


        // //Get api/customer/77/contacts
        // [HttpGet("{id}/contacts")]
        // public IEnumerable<Contact> GetContacts([FromRoute] long id)
        // {
        //     var contacts = _context.Contact
        //          .Where(b => b.CustomerId.Equals(id))
        //          .OrderByDescending(b => b.Id)
        //          .ToList();
        //     return contacts;
        // }


        // //Get api/customer/77/notifications
        // [HttpGet("{id}/notifications")]
        // public IEnumerable<Notification> GetNotifications([FromRoute] long id)
        // {
        //     var notifications = _context.Notification
        //          .Where(b => b.CustomerId.Equals(id))
        //          .OrderByDescending(b => b.SentDate)
        //          .ToList();
        //     return notifications;
        // }


        //Get api/customer/77/name
        [HttpGet("{id}/name")]
        public async Task<IActionResult> GetName([FromRoute] long id)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            //BUGBUG: this is bombing once in a while 
            //System.InvalidOperationException: Sequence contains no elements
            //on this client url 
            //http://localhost:5000/default.htm#!/customerSites/85

            var ret = await _context.Customer
            .Select(r => new { r.Id, r.Name })
                           .Where(r => r.Id == id)
                           .FirstAsync();
            return Ok(ret);
        }





        //-------------
        //CRUD ROUTES
        //-------------

        // GET: api/Customer
        //????? DA FUCK IS THIS ROUTE FOR ?????
        [HttpGet]
        public IEnumerable<Customer> GetCustomer()
        {
            return _context.Customer;
        }




        // GET: api/Customer/5
        [HttpGet("{id}")]
        public async Task<IActionResult> GetCustomer([FromRoute] long id)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var customer = await _context.Customer.SingleOrDefaultAsync(m => m.Id == id);

            if (customer == null)
            {
                return NotFound();
            }

            return Ok(customer);
        }

        // PUT: api/Customer/5
        [HttpPut("{id}")]
        public async Task<IActionResult> PutCustomer([FromRoute] long id, [FromBody] Customer customer)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            if (id != customer.Id)
            {
                return BadRequest();
            }

            _context.Entry(customer).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!CustomerExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }


            return NoContent();
        }

        // POST: api/Customer
        [HttpPost]
        public async Task<IActionResult> PostCustomer([FromBody] Customer customer)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            _context.Customer.Add(customer);
            await _context.SaveChangesAsync();

            return CreatedAtAction("GetCustomer", new { id = customer.Id }, customer);
        }

        // DELETE: api/Customer/5
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteCustomer([FromRoute] long id)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var customer = await _context.Customer.SingleOrDefaultAsync(m => m.Id == id);
            if (customer == null)
            {
                return NotFound();
            }

            _context.Customer.Remove(customer);
            await _context.SaveChangesAsync();

            return Ok(customer);
        }

        private bool CustomerExists(long id)
        {
            return _context.Customer.Any(e => e.Id == id);
        }
    }
}