
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using rockfishCore.Models;
using rockfishCore.Util;
using System.Linq;
using System;

//requried to inject configuration in constructor
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Authorization;

using Microsoft.EntityFrameworkCore;

namespace rockfishCore.Controllers
{
    [Produces("application/json")]
    [Route("api/report")]
    [Authorize]
    public class ReportController : Controller
    {
        private readonly rockfishContext _context;
        private readonly IConfiguration _configuration;
        public ReportController(rockfishContext context, IConfiguration configuration)//these two are injected, see startup.cs
        {
            _context = context;
            _configuration = configuration;
        }

      

        ///////////////////////////////////////////////////////
        //Get expiring subscriptions list
        //
        [HttpGet("expires")]
        public JsonResult Get()
        {
            var customerList = _context.Customer.Select(p => new { p.Id, p.Name });

            var rawExpiresList = _context.Purchase
            .Where(p => p.ExpireDate != null && p.CancelDate == null)
            .OrderBy(p => p.ExpireDate)
            .Select(p => new expiresResultItem { id = p.Id, expireDate = p.ExpireDate, name = p.Name, site_id = p.SiteId, customerId = p.CustomerId })
            .ToList();

            foreach (expiresResultItem i in rawExpiresList)
            {
                i.Customer = customerList.First(p => p.Id == i.customerId).Name;
            }

            return Json(rawExpiresList);
        }

        //dto classes for route
        public class expiresResultItem
        {
            public long id;
            public string name;
            public string Customer;
            public long customerId;
            public long? expireDate;
            public long site_id;

        }



        ///////////////////////////////////////////////////////
        //Get unique product code / name combinations
        //
        [HttpPost("emailsforproductcodes")]
        public JsonResult GetUniqueEmailsByProductCodes([FromBody] requestEmailsForProductCodes req)
        {
            var customerList = _context.Customer.Select(p => new { p.Id, p.DoNotContact });

            List<long> rawCustomerIds = new List<long>();

            foreach (string pcode in req.products)
            {
                //fetch all customer id's from purchase collection that match product codes submitted
                var l = _context.Purchase.Where(p => p.ProductCode == pcode).Select(p => p.CustomerId).Distinct();
                rawCustomerIds.AddRange(l.ToList());
            }

            //uniquify the customer list
            List<long> uniqueCustomerIds = rawCustomerIds.Distinct().ToList();

            //container for the raw email lists built serially
            List<string> rawEmails = new List<string>();

            foreach (long cid in uniqueCustomerIds)
            {
                //skip if do not contact and not explicitly including do not contact
                if (customerList.First(p => p.Id == cid).DoNotContact && req.ckNoContact != true)
                    continue;

                //get all raw email values for this client from db
                //there may be dupes or even multiple in one 
                rawEmails.AddRange(getEmailsForClient(cid));
            }

            //Now clean up the list and sort and uniquify it           
            List<string> cleanedEmails = cleanupRawEmailList(rawEmails);

            return Json(cleanedEmails);
        }


        //Given a client id find all unique email address in db for that client
        private List<string> getEmailsForClient(long id)
        {
            List<string> ret = new List<string>();
          
            //New for RF 6
            var cust = _context.Customer.Where(p => p.Id == id).FirstOrDefault();
            if (cust != null)
            {
                if (!string.IsNullOrWhiteSpace(cust.AdminEmail))
                    ret.Add(cust.AdminEmail);
                if (!string.IsNullOrWhiteSpace(cust.SupportEmail))
                    ret.Add(cust.SupportEmail);
            }

          //TOASTED for RF 6
            //search contact, trial, purchase, incident (optionally)
            // ret.AddRange(_context.Purchase.Where(p => p.CustomerId == id).Select(p => p.Email).Distinct().ToList());
            // ret.AddRange(_context.Contact.Where(p => p.CustomerId == id).Select(p => p.Email).Distinct().ToList());
            // ret.AddRange(_context.Trial.Where(p => p.CustomerId == id).Select(p => p.Email).Distinct().ToList());
            // if (includeIncidentEmails)
            //     ret.AddRange(_context.Incident.Where(p => p.CustomerId == id).Select(p => p.Email).Distinct().ToList());
            return ret;
        }


        //break out multiple also trim whitespace and lowercase and uniquify them
        private List<string> cleanupRawEmailList(List<string> src)
        {
            List<string> ret = new List<string>();
            foreach (string rawAddress in src)
            {
                //count the @'s, if there are more than one then get splittn'
                int count = rawAddress.Count(f => f == '@');

                if (count < 1)
                    continue;//no address, skip this one

                //a little cleanup based on what I had to do in og rockfish
                string semiRawAddress = rawAddress.Replace(", ", ",").TrimEnd('>').TrimEnd(',').Trim();

                //there's at least one address in there, maybe more
                if (count == 1)
                    ret.Add(semiRawAddress.ToLowerInvariant());
                else
                {
                    //there are multiple so break it apart
                    //determine break character could be a space or a comma
                    char breakChar;
                    if (semiRawAddress.Contains(','))
                    {
                        breakChar = ',';
                    }
                    else if (semiRawAddress.Contains(' '))
                    {
                        breakChar = ' ';
                    }
                    else
                    {
                        //no break character, it's a bad address, highlight it so it can be fixed when seen
                        ret.Add("_BAD_EMAIL_" + semiRawAddress + "_BAD_EMAIL_");
                        continue;
                    }

                    //Ok if we made it here then we can split out the emails
                    string[] splits = semiRawAddress.Split(breakChar);
                    foreach (string s in splits)
                    {
                        if (!string.IsNullOrWhiteSpace(s) && s.Contains("@"))
                            ret.Add(s.ToLowerInvariant().Trim());
                    }
                }
            }

            //return distinct values only that are ordered by the email domain
            return ret.Distinct().OrderBy(email => email.Split('@')[1]).ToList();
        }


        //dto classes for route
        public class requestEmailsForProductCodes
        {
            public string[] products;
            public bool ckIncidental;
            public bool ckNoContact;
        }
        /////////////////////////////////////////////////////////////////////////////////////



    }//eoc
}//eons

