using Managing.Api.Models.Responses;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Domain.Scenarios;
using Managing.Domain.Strategies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using static Managing.Common.Enums;

namespace Managing.Api.Controllers;

/// <summary>
/// Controller for managing scenarios and strategies within the application.
/// Provides endpoints for creating, retrieving, and deleting scenarios and strategies.
/// Requires authorization for access and produces JSON responses.
/// </summary>
[ApiController]
[Authorize]
[Route("[controller]")]
[Produces("application/json")]
public class ScenarioController : BaseController
{
    private readonly IScenarioService _scenarioService;

    /// <summary>
    /// Initializes a new instance of the <see cref="ScenarioController"/> class.
    /// </summary>
    /// <param name="scenarioService">The service for managing scenarios.</param>
    /// <param name="userService">The service for user-related operations.</param>
    public ScenarioController(
        IScenarioService scenarioService,
        IUserService userService)
        : base(userService)
    {
        _scenarioService = scenarioService;
    }

    /// <summary>
    /// Retrieves all scenarios for the authenticated user.
    /// </summary>
    /// <returns>A list of scenarios.</returns>
    [HttpGet]
    public async Task<ActionResult<IEnumerable<ScenarioViewModel>>> GetScenarios()
    {
        var user = await GetUser();
        var scenarios = await _scenarioService.GetScenariosByUserAsync(user);
        var scenarioViewModels = scenarios.Select(MapToScenarioViewModel);
        return Ok(scenarioViewModels);
    }

    /// <summary>
    /// Creates a new scenario with the specified name and strategies for the authenticated user.
    /// </summary>
    /// <param name="name">The name of the scenario.</param>
    /// <param name="strategies">A list of strategy names to include in the scenario.</param>
    /// <returns>The created scenario.</returns>
    [HttpPost]
    public async Task<ActionResult<ScenarioViewModel>> CreateScenario(string name, List<string> strategies,
        int? loopbackPeriod = null)
    {
        var user = await GetUser();
        var scenario = await _scenarioService.CreateScenarioForUser(user, name, strategies, loopbackPeriod);
        var scenarioViewModel = MapToScenarioViewModel(scenario);
        return Ok(scenarioViewModel);
    }

    /// <summary>
    /// Deletes a scenario by name for the authenticated user.
    /// </summary>
    /// <param name="name">The name of the scenario to delete.</param>
    /// <returns>An ActionResult indicating the outcome of the operation.</returns>
    [HttpDelete]
    public async Task<ActionResult> DeleteScenario(string name)
    {
        var user = await GetUser();
        return Ok(await _scenarioService.DeleteScenarioByUser(user, name));
    }

    // Update scenario
    [HttpPut]
    public async Task<ActionResult> UpdateScenario(string name, List<string> strategies, int? loopbackPeriod = null)
    {
        var user = await GetUser();
        return Ok(await _scenarioService.UpdateScenarioByUser(user, name, strategies, loopbackPeriod));
    }

    /// <summary>
    /// Retrieves all strategies for the authenticated user.
    /// </summary>
    /// <returns>A list of strategies.</returns>
    [HttpGet]
    [Route("indicator")]
    public async Task<ActionResult<IEnumerable<IndicatorViewModel>>> GetIndicators()
    {
        var user = await GetUser();
        var indicators = await _scenarioService.GetIndicatorsAsync();
        var indicatorViewModels = indicators.Select(MapToIndicatorViewModel);
        return Ok(indicatorViewModels);
    }

    /// <summary>
    /// Creates a new indicator with specified parameters for the authenticated user.
    /// </summary>
    /// <param name="indicatorType">The type of the indicator.</param>
    /// <param name="name">The name of the indicator.</param>
    /// <param name="period">The period for the indicator (optional).</param>
    /// <param name="fastPeriods">The fast periods for the indicator (optional).</param>
    /// <param name="slowPeriods">The slow periods for the indicator (optional).</param>
    /// <param name="signalPeriods">The signal periods for the indicator (optional).</param>
    /// <param name="multiplier">The multiplier for the indicator (optional).</param>
    /// <param name="stochPeriods">The stochastic periods for the indicator (optional).</param>
    /// <param name="smoothPeriods">The smooth periods for the indicator (optional).</param>
    /// <param name="cyclePeriods">The cycle periods for the indicator (optional).</param>
    /// <returns>The created indicator.</returns>
    [HttpPost]
    [Route("indicator")]
    public async Task<ActionResult<IndicatorViewModel>> CreateIndicator(
        IndicatorType indicatorType,
        string name,
        int? period = null,
        int? fastPeriods = null,
        int? slowPeriods = null,
        int? signalPeriods = null,
        double? multiplier = null,
        int? stochPeriods = null,
        int? smoothPeriods = null,
        int? cyclePeriods = null)
    {
        var user = await GetUser();
        var indicator = await _scenarioService.CreateIndicatorForUser(
            user,
            indicatorType,
            name,
            period,
            fastPeriods,
            slowPeriods,
            signalPeriods,
            multiplier,
            stochPeriods,
            smoothPeriods,
            cyclePeriods);
        var indicatorViewModel = MapToIndicatorViewModel(indicator);
        return Ok(indicatorViewModel);
    }

    /// <summary>
    /// Deletes a indicator by name for the authenticated user.
    /// </summary>
    /// <param name="name">The name of the indicator to delete.</param>
    /// <returns>An ActionResult indicating the outcome of the operation.</returns>
    [HttpDelete]
    [Route("indicator")]
    public async Task<ActionResult> DeleteIndicator(string name)
    {
        var user = await GetUser();
        return Ok(await _scenarioService.DeleteIndicatorByUser(user, name));
    }

    // Update indicator
    [HttpPut]
    [Route("indicator")]
    public async Task<ActionResult> Updateindicator(
        IndicatorType indicatorType,
        string name,
        int? period = null,
        int? fastPeriods = null,
        int? slowPeriods = null,
        int? signalPeriods = null,
        double? multiplier = null,
        int? stochPeriods = null,
        int? smoothPeriods = null,
        int? cyclePeriods = null)
    {
        var user = await GetUser();
        return Ok(await _scenarioService.UpdateIndicatorByUser(
            user,
            indicatorType,
            name,
            period,
            fastPeriods,
            slowPeriods,
            signalPeriods,
            multiplier,
            stochPeriods,
            smoothPeriods,
            cyclePeriods));
    }

    private static ScenarioViewModel MapToScenarioViewModel(Scenario scenario)
    {
        return new ScenarioViewModel
        {
            Name = scenario.Name,
            LoopbackPeriod = scenario.LoopbackPeriod,
            UserName = scenario.User?.Name,
            Indicators = scenario.Indicators?.Select(MapToIndicatorViewModel).ToList() ?? new List<IndicatorViewModel>()
        };
    }

    private static IndicatorViewModel MapToIndicatorViewModel(IndicatorBase indicatorBase)
    {
        return new IndicatorViewModel
        {
            Name = indicatorBase.Name,
            Type = indicatorBase.Type,
            SignalType = indicatorBase.SignalType,
            MinimumHistory = indicatorBase.MinimumHistory,
            Period = indicatorBase.Period,
            FastPeriods = indicatorBase.FastPeriods,
            SlowPeriods = indicatorBase.SlowPeriods,
            SignalPeriods = indicatorBase.SignalPeriods,
            Multiplier = indicatorBase.Multiplier,
            SmoothPeriods = indicatorBase.SmoothPeriods,
            StochPeriods = indicatorBase.StochPeriods,
            CyclePeriods = indicatorBase.CyclePeriods,
            UserName = indicatorBase.User?.Name
        };
    }
}