using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using DD.Persistence.Models;
using DD.Persistence.Models.Requests;
using DD.Persistence.Repositories;
using System.Net;

namespace DD.Persistence.API.Controllers;

[ApiController]
[Authorize]
[Route("api/[controller]")]
public class ChangeLogController : ControllerBase, IChangeLogApi
{
    private readonly IChangeLogRepository repository;

    public ChangeLogController(IChangeLogRepository repository)
    {
        this.repository = repository;
    }

    [HttpPost("{idDiscriminator}")]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
    public async Task<IActionResult> Add(
        [FromRoute] Guid idDiscriminator,
        [FromBody] DataWithWellDepthAndSectionDto dto,
        CancellationToken token)
    {
        var userId = User.GetUserId<Guid>();
        var result = await repository.AddRange(userId, idDiscriminator, [dto], token);

        return CreatedAtAction(nameof(Add), result);
    }

    [HttpPost("range/{idDiscriminator}")]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.Created)]
    public async Task<IActionResult> AddRange(
        [FromRoute] Guid idDiscriminator,
        [FromBody] IEnumerable<DataWithWellDepthAndSectionDto> dtos,
        CancellationToken token)
    {
        var userId = User.GetUserId<Guid>();
        var result = await repository.AddRange(userId, idDiscriminator, dtos, token);

        return CreatedAtAction(nameof(AddRange), result);
    }

    [HttpDelete]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
    public async Task<IActionResult> Delete(Guid id, CancellationToken token)
    {
        var userId = User.GetUserId<Guid>();
        var result = await repository.MarkAsDeleted(userId, [id], token);

        return Ok(result);
    }

    [HttpDelete("range")]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
    public async Task<IActionResult> DeleteRange(IEnumerable<Guid> ids, CancellationToken token)
    {
        var userId = User.GetUserId<Guid>();
        var result = await repository.MarkAsDeleted(userId, ids, token);

        return Ok(result);
    }

    [HttpPost("replace/{idDiscriminator}")]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
    public async Task<IActionResult> ClearAndAddRange(
        [FromRoute] Guid idDiscriminator,
        [FromBody] IEnumerable<DataWithWellDepthAndSectionDto> dtos,
        CancellationToken token)
    {
        var userId = User.GetUserId<Guid>();
        var result = await repository.ClearAndAddRange(userId, idDiscriminator, dtos, token);
        return Ok(result);
    }

    [HttpPut]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
    public async Task<IActionResult> Update(
        DataWithWellDepthAndSectionDto dto,
        CancellationToken token)
    {
        var userId = User.GetUserId<Guid>();
        var result = await repository.UpdateRange(userId, [dto], token);

        return Ok(result);
    }

    [HttpPut("range")]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
    public async Task<IActionResult> UpdateRange(
        IEnumerable<DataWithWellDepthAndSectionDto> dtos,
        CancellationToken token)
    {
        var userId = User.GetUserId<Guid>();
        var result = await repository.UpdateRange(userId, dtos, token);

        return Ok(result);
    }

    [HttpGet("{idDiscriminator}")]
    [ProducesResponseType(typeof(PaginationContainer<DataWithWellDepthAndSectionDto>), (int)HttpStatusCode.OK)]
    public async Task<IActionResult> GetCurrent(
        [FromRoute] Guid idDiscriminator,
        [FromQuery] SectionPartRequest filterRequest,
        [FromQuery] PaginationRequest paginationRequest,
        CancellationToken token)
    {
        var moment = new DateTimeOffset(3000, 1, 1, 0, 0, 0, TimeSpan.Zero);
        var result = await repository.GetByDate(idDiscriminator, moment, filterRequest, paginationRequest, token);

        return Ok(result);
    }

    [HttpGet("moment/{idDiscriminator}")]
    [ProducesResponseType(typeof(PaginationContainer<DataWithWellDepthAndSectionDto>), (int)HttpStatusCode.OK)]
    public async Task<IActionResult> GetByDate(
        [FromRoute] Guid idDiscriminator,
        DateTimeOffset moment,
        [FromQuery] SectionPartRequest filterRequest,
        [FromQuery] PaginationRequest paginationRequest,
        CancellationToken token)
    {
        var result = await repository.GetByDate(idDiscriminator, moment, filterRequest, paginationRequest, token);

        return Ok(result);
    }

    [HttpGet("history/{idDiscriminator}")]
    [ProducesResponseType(typeof(IEnumerable<ChangeLogDto>), (int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.NoContent)]
    public async Task<IActionResult> GetChangeLogForDate(
        [FromRoute] Guid idDiscriminator,
        DateTimeOffset dateBegin,
        DateTimeOffset dateEnd,
        CancellationToken token)
    {
        var result = await repository.GetChangeLogForInterval(idDiscriminator, dateBegin, dateEnd, token);

        return Ok(result);
    }

    [HttpGet("datesChange/{idDiscriminator}")]
    [ProducesResponseType(typeof(IEnumerable<DateOnly>), (int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.NoContent)]
    public async Task<IActionResult> GetDatesChange([FromRoute] Guid idDiscriminator, CancellationToken token)
    {
        var result = await repository.GetDatesChange(idDiscriminator, token);

        return Ok(result);
    }

    [HttpGet("part/{idDiscriminator}")]
    [ProducesResponseType(typeof(IEnumerable<DataWithWellDepthAndSectionDto>), (int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.NoContent)]
    public async Task<ActionResult<IEnumerable<DataWithWellDepthAndSectionDto>>> GetPart([FromRoute] Guid idDiscriminator, DateTimeOffset dateBegin, int take = 86400, CancellationToken token = default)
    {
        var result = await repository.GetGtDate(idDiscriminator, dateBegin, token);

        return Ok(result);
    }

    [HttpGet("datesRange/{idDiscriminator}")]
    [ProducesResponseType(typeof(DatesRangeDto), (int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.NoContent)]
    public async Task<ActionResult<DatesRangeDto>> GetDatesRangeAsync([FromRoute] Guid idDiscriminator, CancellationToken token)
    {
        var result = await repository.GetDatesRange(idDiscriminator, token);

        if (result is null)
            return NoContent();

        return Ok(result);
    }
}