using System;
using System.Text.Json;
using Expedience.Api.Encryption;
using Expedience.Infrastructure;
using Expedience.Infrastructure.Models;
using MassTransit;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Expedience.Api.Controllers
{
    [Route("api")]
    [ApiController]
    public class ExpedienceController : ControllerBase
    {
        private readonly ILogger<ExpedienceController> _logger;
        private readonly IPublishEndpoint _publisher;
        private readonly IDecryptor _decrypytor;
        private readonly IServiceScopeFactory _serviceScopeFactory;

        public ExpedienceController(ILogger<ExpedienceController> logger,
            IPublishEndpoint publisher,
            IDecryptor decrypytor,
            IServiceScopeFactory serviceScopeFactory)
        {
            _logger = logger;
            _publisher = publisher;
            _decrypytor = decrypytor;
            _serviceScopeFactory = serviceScopeFactory;
        }

        [HttpPost("DutyCompletion")]
        public async Task<ActionResult> PostDutyCompletionResult(List<string> encryptedPayloads)
        {
            var utcNow = DateTime.UtcNow;
            try
            {
                foreach (var payload in encryptedPayloads)
                {
                    var decryptedData = _decrypytor.Decrypt(payload);
                    var completionResult = JsonSerializer.Deserialize<Models.DutyCompletionResult>(decryptedData)!;
                    completionResult.UploadDateUtc = utcNow;
                    await _publisher.Publish(completionResult);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error publishing completion result: {errorMessage}", ex.Message);
            }

            return Ok();
        }

        [HttpGet("UserName/{worldId}/{userHash}")]
        public async Task<ActionResult> GetUserName(int worldId, string userHash, CancellationToken cancellationToken)
        {
            try
            {
                using var scope = _serviceScopeFactory.CreateScope();
                using var dbContext = scope.ServiceProvider.GetRequiredService<ExpedienceContext>();

                var user = await dbContext.Users.FirstOrDefaultAsync(x => x.UserHash == userHash && x.WorldId == worldId, cancellationToken);
                if (user != null)
                    return Ok(user.UserName);
                else
                    return NotFound();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error obtaining user name for World Id {worldId} and hash {userHash}: {errorMessage}", worldId, userHash, ex.Message);
            }

            return StatusCode(500);
        }

		[HttpGet("DutyCompletionRecords/{expac}")]
		public async Task<ActionResult> GetDutyCompletionRecords(string expac, CancellationToken cancellationToken)
		{
			try
			{
				using var scope = _serviceScopeFactory.CreateScope();
				var repository = scope.ServiceProvider.GetRequiredService<IExpedienceRepository>();

				var results = await repository.GetDutyCompletionRecords(expac, cancellationToken);
				return Ok(results);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "Error getting Duty Completion Records for {expac}: {errorMessage}", expac, ex.Message);
			}

			return StatusCode(500);
		}

		[HttpGet("DeepDungeonRecords")]
		public async Task<ActionResult> GetDeepDungeonRecords(CancellationToken cancellationToken)
		{
			try
			{
				using var scope = _serviceScopeFactory.CreateScope();
				var repository = scope.ServiceProvider.GetRequiredService<IExpedienceRepository>();
				
				var results = await repository.GetDeepDungeonRecords(cancellationToken);
				return Ok(results);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "Error getting Deep Dungeon Records: {errorMessage}", ex.Message);
			}

			return StatusCode(500);
		}

        [HttpGet("TreasureHuntRecords")]
        public async Task<ActionResult> GetTreasureHuntRecords(CancellationToken cancellationToken)
        {
            try
            {
                using var scope = _serviceScopeFactory.CreateScope();
                var repository = scope.ServiceProvider.GetRequiredService<IExpedienceRepository>();

                var results = await repository.GetContentTypeRecords("Treasure Hunt", cancellationToken);
                return Ok(results);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting Treasure Hunt Records: {errorMessage}", ex.Message);
            }

            return StatusCode(500);
        }

        [HttpGet("TopX/{recordType}/{territoryId}/{limit}")]
        public async Task<ActionResult> GetTopXRecords(int recordType, int territoryId, int limit, CancellationToken cancellationToken)
        {
            try
            {
                using var scope = _serviceScopeFactory.CreateScope();
                var repository = scope.ServiceProvider.GetRequiredService<IExpedienceRepository>();

                var records = await repository.GetTopXRecords(recordType, territoryId, limit, cancellationToken);

                var results = new List<DutyCompletionResult>();
                foreach (var record in records)
                {
                    var dcr = record.DutyCompletionResult;
                    var territory = record.Territory;
                    var user = record.User;

                    var dutyCompletionResult = new DutyCompletionResult
                    {
                        Id = dcr.Id,
                        UserId = user.UserId,
                        TerritoryId = territory.TerritoryId,
                        IsMinILevel = recordType == 3,
                        HasNpcMembers = recordType == 4,
                        StartTime = dcr.StartTime,
                        EndTime = dcr.EndTime,
                        Hours = dcr.Hours,
                        Minutes = dcr.Minutes,
                        Seconds = dcr.Seconds,
                        Milliseconds = dcr.Milliseconds,
                        GameVersion = dcr.GameVersion,
                        PluginVersion = dcr.PluginVersion,
                        Lang = dcr.Lang,
                        UploadedAt = dcr.UploadedAt,
                        DutyMembers = record.DutyMembers.Select(dm => new DutyMember
                        {
                            ClassJob = dm.ClassJob,
                            IsNpc = dm.IsNpc,
                            IsPlayer = dm.IsPlayer,
                            Level = dm.Level,
                            GroupNumber = dm.GroupNumber,
                            MemberNumber = dm.MemberNumber,
                        }).ToList(),
                        Territory = new Models.Territory
                        {
                            TerritoryId = dcr.TerritoryId,
                            PlaceName = territory.PlaceName,
                            ContentId = String.Empty,
                            ContentName = territory.ContentName,
                            ContentType = territory.ContentType,
                            Expac = territory.Expac,
                            Level = territory.Level,
                        },
                        User = new User
                        {
                            UserId = user.UserId,
                            UserName = user.UserName,
                            UserHash = String.Empty,
                            WorldId = user.WorldId,
                        },
                        DataCenter = dcr.DataCenter,
                    };

                    results.Add(dutyCompletionResult);
                }
                return Ok(results);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting Top X Records: {errorMessage}", ex.Message);
            }

            return StatusCode(500);
        }
    }
}
