﻿namespace Percepolis.Web.Api
{
    using Data;
    using Data.Entities;
    using Percepolis.Csa;
    using Services;
    using Services.Interfaces;
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Web;
    using System.Web.Http;
    using System.Web.Http.Description;

    [Authorize]
    [RoutePrefix("api/csa")]
    public class ScheduleController : ApiController
    {
        private PercepolisDbContext _db;
        private IInstitutionService _institutionService;

        public ScheduleController()
        {
            _db = new PercepolisDbContext();
            _institutionService = new InstitutionService(_db);
        }

        [Authorize]
        [HttpGet, Route("")]
        public async Task<IHttpActionResult> Get(int uid, double maxCredits)
        {
            try
            {
                var target = _db.Users.Find(uid);
                var curricula = target.Curricula.Select(e => e.Curriculum).ToList();
                var requirements = target.Curricula.SelectMany(e => e.Curriculum.Requirements).ToList();
                var courses = requirements.SelectMany(e => e.Courses.Select(c => c.Course)).ToList();
                var semesters = await _db.Semesters.ToListAsync();

                // Stage 1 - Course Selection
                var csProblem = new CourseSelector(target, curricula, requirements, courses, "CBC_MIXED_INTEGER_PROGRAMMING")
                {
                    OutputEnabled = true
                };
                csProblem.Initialize();
                var selectedCourses = csProblem.Solve();

                // Stage 2 - Course Scheduling
                var ssProblem = new CourseScheduler(target, semesters, selectedCourses);
                var schedule = ssProblem.Solve(DateTime.UtcNow, maxCredits);
                var semestersUsed = schedule.Where(e => e.Value.Any()).ToList();
                var formatted = new List<Tuple<object, List<object>>>();
                foreach(var s in semestersUsed)
                {
                    var neutralSemesters = new { Name = s.Key.ToString(), MaxCredits = s.Key.MaxCredits };
                    var neutralCourses = new List<object>();
                    foreach(var c in s.Value)
                    {
                        neutralCourses.Add(new { Id = c.Id, Name = c.Code, Credits = c.Credits, Description = c.Description });
                    }

                    var tuple = new Tuple<object, List<object>>(neutralSemesters, neutralCourses);
                    formatted.Add(tuple);
                }

                
                if (formatted.Any())
                    return Json(formatted);
                else
                    return NotFound();
            }
            catch (Exception)
            {
                return BadRequest("Retrieving schedule failed.");
            }
        }

        [Authorize]
        [HttpGet, Route("{id:int}")]
        public async Task<IHttpActionResult> Get(int id)
        {
            try
            {
                var entity = await _institutionService.GetByIdAsync(id);
                if (entity != null)
                    return Ok(new { entity.Name, entity.Website });
                else
                    return NotFound();
            }
            catch (Exception)
            {
                return BadRequest("Retrieving institutions failed.");
            }
        }
    }
}