using DysonNetwork.Shared.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace DysonNetwork.Pass.Account;
/// 
/// Controller for managing user presence activities with lease-based expiration.
/// Supports both user-defined manual IDs and autogenerated GUIDs for activity management.
/// 
[ApiController]
[Route("/api/activities")]
public class PresenceActivityController(AppDatabase db, AccountEventService service)
    : ControllerBase
{
    /// 
    /// Retrieves active (non-expired) presence activities for the authenticated user.
    /// Optionally includes expired activities if includeExpired is true.
    /// 
    /// Whether to include expired activities
    /// The number of activities to skip for pagination
    /// The maximum number of activities to return
    /// List of presence activities
    [HttpGet]
    [ProducesResponseType>(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task>> GetActivities(
        [FromQuery] bool includeExpired = false,
        [FromQuery] int offset = 0,
        [FromQuery] int take = 20
    )
    {
        if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser)
            return Unauthorized();
        List activities;
        if (includeExpired)
        {
            (activities, var total) = await service.GetAllActivities(currentUser.Id, offset, take);
            Response.Headers["X-Total"] = total.ToString();
        }
        else
        {
            activities = await service.GetActiveActivities(currentUser.Id);
        }
        return Ok(activities);
    }
    /// 
    /// Retrieves active presence activities for any user account (admin/debugging endpoint).
    /// 
    /// List of active presence activities
    [HttpGet("{identifier}")]
    [ProducesResponseType>(StatusCodes.Status200OK)]
    public async Task>> GetActivitiesByAccountId(
        string identifier
    )
    {
        var account = Guid.TryParse(identifier, out var identifierGuid)
            ? await db.Accounts.FirstOrDefaultAsync(a => a.Id == identifierGuid)
            : await db.Accounts.FirstOrDefaultAsync(a => a.Name == identifier);
        if (account is null)
            return NotFound();
        var activities = await service.GetActiveActivities(account.Id);
        return Ok(activities);
    }
    /// 
    /// Creates or updates a presence activity with lease expiration.
    /// If an activity with the same 'manualId' exists, it will be updated.
    /// Otherwise, a new activity will be created.
    /// 
    /// Activity creation or update parameters
    /// The created or updated activity
    [HttpPost]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task> SetActivity(
        [FromBody] SetActivityRequest request
    )
    {
        if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser)
            return Unauthorized();
        if (!string.IsNullOrWhiteSpace(request.ManualId))
        {
            var result = await service.UpdateActivityByManualId(
                request.ManualId,
                currentUser.Id,
                activity =>
                {
                    if (request.Type.HasValue)
                        activity.Type = request.Type.Value;
                    activity.Title = request.Title;
                    activity.Subtitle = request.Subtitle;
                    activity.Caption = request.Caption;
                    activity.LargeImage = request.LargeImage;
                    activity.SmallImage = request.SmallImage;
                    activity.TitleUrl = request.TitleUrl;
                    activity.SubtitleUrl = request.SubtitleUrl;
                    activity.Meta = request.Meta;
                },
                request.LeaseMinutes
            );
            if (result != null)
            {
                return Ok(result);
            }
        }
        if (!request.Type.HasValue)
            return BadRequest("Type is required when creating a new activity");
        var newActivity = new SnPresenceActivity
        {
            AccountId = currentUser.Id,
            Type = request.Type.Value,
            ManualId = request.ManualId,
            Title = request.Title,
            Subtitle = request.Subtitle,
            Caption = request.Caption,
            LargeImage = request.LargeImage,
            SmallImage = request.SmallImage,
            TitleUrl = request.TitleUrl,
            SubtitleUrl = request.SubtitleUrl,
            Meta = request.Meta
        };
        var createResult = await service.SetActivity(newActivity, request.LeaseMinutes);
        return Ok(createResult);
    }
    /// 
    /// Updates an existing presence activity using either its GUID or manual ID.
    /// 
    /// System-generated GUID of the activity (optional)
    /// Update parameters (only provided fields are updated)
    /// The updated activity
    /// One of 'id' or 'manualId' must be provided and non-empty.
    [HttpPut("{id:guid}")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task> UpdateActivity(
        [FromRoute] Guid id,
        [FromBody] SetActivityRequest request
    )
    {
        if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser)
            return Unauthorized();
        var result = await service.UpdateActivity(
            id,
            currentUser.Id,
            activity =>
            {
                if (request.Type.HasValue)
                    activity.Type = request.Type.Value;
                if (request.Title != null)
                    activity.Title = request.Title;
                if (request.Subtitle != null)
                    activity.Subtitle = request.Subtitle;
                if (request.Caption != null)
                    activity.Caption = request.Caption;
                if (request.ManualId != null)
                    activity.ManualId = request.ManualId;
                if (request.Meta != null)
                    activity.Meta = request.Meta;
            },
            request.LeaseMinutes
        );
        return Ok(result);
    }
    /// 
    /// Deletes a presence activity using either its GUID or manual ID.
    /// 
    /// System-generated GUID of the activity (optional)
    /// User-defined manual ID of the activity (optional)
    /// NoContent on success
    /// One of 'id' or 'manualId' must be provided and non-empty. Soft-deletes the activity.
    [HttpDelete]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task DeleteActivityById(
        [FromQuery] string? id,
        [FromQuery] string? manualId
    )
    {
        if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser)
            return Unauthorized();
        if (!string.IsNullOrWhiteSpace(manualId))
        {
            var deleted = await service.DeleteActivityByManualId(manualId, currentUser.Id);
            if (!deleted)
                return NotFound();
            return NoContent();
        }
        if (string.IsNullOrWhiteSpace(id) || !Guid.TryParse(id, out var activityGuid))
            return BadRequest("Either 'id' (GUID) or 'manualId' must be provided");
        {
            var deleted = await service.DeleteActivity(activityGuid, currentUser.Id);
            if (!deleted)
                return NotFound();
            return NoContent();
        }
    }
    /// 
    /// Request model for creating a new presence activity.
    /// 
    public class SetActivityRequest
    {
        /// The type of presence activity (e.g., Gaming, Music, Workout)
        public PresenceType? Type { get; set; }
        /// User-defined identifier for the activity (optional, for easy reference)
        public string? ManualId { get; set; }
        /// Main title of the activity
        public string? Title { get; set; }
        /// Secondary subtitle of the activity
        public string? Subtitle { get; set; }
        /// Additional caption/description
        public string? Caption { get; set; }
        /// Large image URL or base64 string
        public string? LargeImage { get; set; }
        /// Small image URL or base64 string
        public string? SmallImage { get; set; }
        /// Title URL
        public string? TitleUrl { get; set; }
        /// Subtitle URL
        public string? SubtitleUrl { get; set; }
        /// Extensible metadata dictionary for custom developer data
        public Dictionary? Meta { get; set; }
        /// Lease duration in minutes (1-60, default: 5)
        public int LeaseMinutes { get; set; } = 5;
    }
}