using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
using JobTrackerApi.Data;
using JobTrackerApi.Services;
using System.Security.Claims;

namespace JobTrackerApi.Controllers
{
    [ApiController]
    [Route("api/export")]
    [Authorize(AuthenticationSchemes = "local")]
    public class ExportController : ControllerBase
    {
        private readonly JobTrackerContext _db;
        private readonly AccountDataExportService? _accountExport;
        private readonly TimeProvider _timeProvider;

        public ExportController(JobTrackerContext db, AccountDataExportService? accountExport = null, TimeProvider? timeProvider = null)
        {
            _db = db;
            _accountExport = accountExport;
            _timeProvider = timeProvider ?? TimeProvider.System;
        }

        [HttpPost("account")]
        [EnableRateLimiting("account-data")]
        public async Task<IActionResult> ExportAccount(CancellationToken cancellationToken)
        {
            var ownerUserId = LocalAuthIdentity.GetRequiredUserId(User);
            if (ownerUserId is null) return Unauthorized();
            if (_accountExport is null) throw new InvalidOperationException("Account export is not configured.");

            var sessionId = User.FindFirstValue("sid");
            var recentCutoff = _timeProvider.GetUtcNow().AddMinutes(-15);
            var currentSession = string.IsNullOrWhiteSpace(sessionId)
                ? null
                : await _db.UserSessions.IgnoreQueryFilters().AsNoTracking()
                    .FirstOrDefaultAsync(item => item.Id == sessionId && item.UserId == ownerUserId, cancellationToken);
            var recentlyAuthenticated = currentSession is { RevokedAtUtc: null } && currentSession.CreatedAtUtc >= recentCutoff;
            if (!recentlyAuthenticated)
            {
                return StatusCode(StatusCodes.Status403Forbidden, new ProblemDetails
                {
                    Title = "Recent sign-in required",
                    Detail = "Sign in again before downloading a complete account export.",
                });
            }

            var artifact = await _accountExport.CreateAsync(ownerUserId, cancellationToken);
            var stream = new FileStream(artifact.StoragePath, FileMode.Open, FileAccess.Read, FileShare.Read, 64 * 1024, FileOptions.Asynchronous | FileOptions.DeleteOnClose);
            return File(stream, "application/zip", artifact.DownloadFileName);
        }

        [HttpGet("jobs")]
        public async Task<IActionResult> ExportJobs(
            [FromQuery] string format = "json",
            [FromQuery] bool includeDeleted = false,
            CancellationToken cancellationToken = default
        )
        {
            var query = _db.JobApplications
                .AsNoTracking()
                .Include(j => j.Company)
                .AsQueryable();

            if (!includeDeleted) query = query.Where(j => !j.IsDeleted);

            var jobs = await query
                .OrderByDescending(j => j.DateApplied)
                .ToListAsync(cancellationToken);

            var stamp = DateTime.Now.ToString("yyyy-MM-dd");

            if (string.Equals(format, "csv", StringComparison.OrdinalIgnoreCase))
            {
                static string Esc(string? s)
                {
                    s ??= "";
                    var needs = s.Contains(',') || s.Contains('"') || s.Contains('\n') || s.Contains('\r');
                    var q = s.Replace("\"", "\"\"");
                    return needs ? $"\"{q}\"" : q;
                }

                var sb = new StringBuilder();
                sb.AppendLine(string.Join(",",
                    "Company",
                    "CompanyLocation",
                    "CompanySource",
                    "JobTitle",
                    "Status",
                    "DateApplied",
                    "Location",
                    "Salary",
                    "SalaryMin",
                    "SalaryMax",
                    "SalaryCurrency",
                    "SalaryPeriod",
                    "NextAction",
                    "FollowUpAt",
                    "JobUrl",
                    "Notes",
                    "CoverLetterText"
                ));

                foreach (var j in jobs)
                {
                    sb.AppendLine(string.Join(",",
                        Esc(j.Company?.Name),
                        Esc(j.Company?.Location),
                        Esc(j.Company?.Source),
                        Esc(j.JobTitle),
                        Esc(j.Status),
                        Esc(j.DateApplied?.ToString("o")),
                        Esc(j.Location),
                        Esc(j.Salary),
                        Esc(j.SalaryMin?.ToString(System.Globalization.CultureInfo.InvariantCulture)),
                        Esc(j.SalaryMax?.ToString(System.Globalization.CultureInfo.InvariantCulture)),
                        Esc(j.SalaryCurrency),
                        Esc(j.SalaryPeriod),
                        Esc(j.NextAction),
                        Esc(j.FollowUpAt?.ToString("o")),
                        Esc(j.JobUrl),
                        Esc(j.Notes),
                        Esc(j.CoverLetterText)
                    ));
                }

                return File(Encoding.UTF8.GetBytes(sb.ToString()), "text/csv", $"job-tracker-export-{stamp}.csv");
            }

            return File(System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(jobs), "application/json", $"job-tracker-export-{stamp}.json");
        }
    }
}

