using JobTrackerApi.Data;
using JobTrackerApi.Models;

namespace JobTrackerApi.Services;

// Phase 5.6 — emitting the lifecycle events the timeline already knows how to read.
//
// JobEvent stays the single history source: this adds rows to it, it does not add a second store.
// Every emitter lives here rather than at each call site, so the two status-change boundaries in
// JobApplicationsController cannot drift apart, and a third boundary gets the behaviour for free.
//
// Events are derived from the TRANSITION, not from the resulting state, so one user action produces
// at most one lifecycle event and re-saving an unchanged status produces none.
// docs/architecture/application-workspace.md.
public static class JobLifecycleEvents
{
    // Records the status change itself plus, when the transition warrants it, one lifecycle event.
    // Replaces the hand-written StatusChanged block at each call site.
    public static void RecordStatusChange(JobTrackerContext db, JobApplication job, string? oldStatus, DateTime at)
    {
        var from = oldStatus ?? string.Empty;
        var to = job.Status ?? string.Empty;
        if (string.Equals(from, to, StringComparison.OrdinalIgnoreCase)) return;

        db.JobEvents.Add(new JobEvent
        {
            JobApplicationId = job.Id,
            Type = "StatusChanged",
            OldValue = oldStatus,
            NewValue = job.Status,
            At = at,
        });

        var lifecycle = LifecycleFor(from, to);
        if (lifecycle is null) return;

        db.JobEvents.Add(new JobEvent
        {
            JobApplicationId = job.Id,
            Type = lifecycle,
            // Useful metadata: which transition produced it, so the timeline can say more than the type.
            OldValue = oldStatus,
            NewValue = job.Status,
            At = at,
        });
    }

    // At most one lifecycle event per transition. Ordered so an Interview -> Offer move reports the
    // offer, which is the thing the user actually cares about.
    private static string? LifecycleFor(string from, string to)
    {
        var wasInterview = IsInterviewStage(from);
        var isInterview = IsInterviewStage(to);

        if (IsOfferStage(to) && !IsOfferStage(from)) return "OfferReceived";
        if (isInterview && !wasInterview) return "InterviewScheduled";

        // Only counts as completed when the application moved FORWARD out of the interview stage.
        // Dragging a card back to an earlier stage is a correction, not a completed interview.
        if (wasInterview && !isInterview && JobPipeline.OrderOf(to) > JobPipeline.OrderOf(from))
        {
            return "InterviewCompleted";
        }

        return null;
    }

    // Emitted when a follow-up checklist item is ticked off. The task itself stays a checklist item —
    // this only records that it happened.
    public static void RecordFollowUpCompleted(JobTrackerContext db, int jobApplicationId, string title)
    {
        db.JobEvents.Add(new JobEvent
        {
            JobApplicationId = jobApplicationId,
            Type = "FollowUpCompleted",
            NewValue = title,
            At = DateTime.Now,
        });
    }

    private static bool IsInterviewStage(string? status) =>
        (status ?? string.Empty).Contains("interview", StringComparison.OrdinalIgnoreCase);

    private static bool IsOfferStage(string? status) =>
        (status ?? string.Empty).Contains("offer", StringComparison.OrdinalIgnoreCase);
}
