using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace JobTrackerApi.Controllers;

[ApiController]
[Route("api/jobapplications")]
[Authorize(AuthenticationSchemes = "local")]
public sealed class JobApplicationLifecycleController : ControllerBase
{
    private readonly JobTrackerContext _db;

    public JobApplicationLifecycleController(JobTrackerContext db)
    {
        _db = db;
    }

    /// <summary>Canonical ordered pipeline stages so the UI renders one source of truth.</summary>
    [HttpGet("pipeline")]
    public ActionResult<IEnumerable<PipelineStageDto>> GetPipeline()
        => Ok(JobPipeline.Stages.Select(stage => new PipelineStageDto(
            stage.Key,
            stage.Order,
            stage.Category.ToString(),
            stage.Group.ToString())));

    [HttpDelete("{id:int}")]
    public async Task<IActionResult> SoftDelete([FromRoute] int id, CancellationToken cancellationToken)
    {
        var job = await _db.JobApplications.FirstOrDefaultAsync(item => item.Id == id, cancellationToken);
        if (job is null) return NotFound();

        if (!job.IsDeleted)
        {
            job.IsDeleted = true;
            job.DeletedAt = DateTime.Now;
            _db.JobEvents.Add(new JobEvent
            {
                JobApplicationId = job.Id,
                Type = "Deleted",
                At = DateTime.Now
            });
            await _db.SaveChangesAsync(cancellationToken);
        }

        return NoContent();
    }

    [HttpPost("{id:int}/restore")]
    public async Task<IActionResult> Restore([FromRoute] int id, CancellationToken cancellationToken)
    {
        var job = await _db.JobApplications.FirstOrDefaultAsync(item => item.Id == id, cancellationToken);
        if (job is null) return NotFound();

        if (job.IsDeleted)
        {
            job.IsDeleted = false;
            job.DeletedAt = null;
            _db.JobEvents.Add(new JobEvent
            {
                JobApplicationId = job.Id,
                Type = "Restored",
                At = DateTime.Now
            });
            await _db.SaveChangesAsync(cancellationToken);
        }

        return NoContent();
    }

    [HttpPatch("{id:int}/followup")]
    public async Task<IActionResult> SetFollowUp(
        [FromRoute] int id,
        [FromBody] FollowUpRequest request,
        CancellationToken cancellationToken)
    {
        var job = await _db.JobApplications.FirstOrDefaultAsync(item => item.Id == id, cancellationToken);
        if (job is null) return NotFound();

        var old = job.FollowUpAt?.ToString("o");
        job.FollowUpAt = request.FollowUpAt;
        _db.JobEvents.Add(new JobEvent
        {
            JobApplicationId = job.Id,
            Type = "FollowUpSet",
            OldValue = old,
            NewValue = request.FollowUpAt?.ToString("o"),
            At = DateTime.Now
        });

        await _db.SaveChangesAsync(cancellationToken);
        return NoContent();
    }

    [HttpGet("{id:int}/history")]
    public async Task<ActionResult<List<JobEventDto>>> GetHistory(
        [FromRoute] int id,
        CancellationToken cancellationToken)
    {
        var exists = await _db.JobApplications.AnyAsync(item => item.Id == id, cancellationToken);
        if (!exists) return NotFound();

        var items = await _db.JobEvents
            .AsNoTracking()
            .Where(item => item.JobApplicationId == id)
            .OrderByDescending(item => item.At)
            .Select(item => new JobEventDto(
                item.Id,
                item.Type,
                item.OldValue,
                item.NewValue,
                item.Note,
                item.At))
            .ToListAsync(cancellationToken);

        return Ok(items);
    }
}
