using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using JobTrackerApi.Data;
using JobTrackerApi.Models;
using System.Security.Claims;

namespace JobTrackerApi.Controllers
{
    [ApiController]
    // Explicitly authorized. These endpoints are all tenant-scoped user data, so they must not
    // depend on the Auth:Require fallback policy being switched on: a deployment that lost that flag
    // would otherwise serve them anonymously. docs/production-readiness-review.md.
    [Route("api/companies")]
    [Authorize(AuthenticationSchemes = "local")]
    public class CompaniesController : ControllerBase
    {
        private readonly JobTrackerContext _db;

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

        private string? CurrentUserId =>
            User?.FindFirstValue(ClaimTypes.NameIdentifier) ?? User?.FindFirstValue("sub");

        private static string? NormalizeSource(string? source)
        {
            if (string.IsNullOrWhiteSpace(source)) return null;
            var value = source.Trim();

            if (Uri.TryCreate(value, UriKind.Absolute, out var uri) && !string.IsNullOrWhiteSpace(uri.Host))
            {
                value = uri.Host;
            }

            value = value.Replace("www.", "", StringComparison.OrdinalIgnoreCase).Trim().Trim('/');
            var lower = value.ToLowerInvariant();

            return lower switch
            {
                "linkedin" or "linkedin.com" => "LinkedIn",
                "finn" or "finn.no" => "Finn",
                "nav" or "nav.no" => "NAV",
                "jobbnorge" or "jobbnorge.no" => "Jobbnorge",
                _ => string.Join(" ", value.Split(new[] { ' ', '-', '_' }, StringSplitOptions.RemoveEmptyEntries).Select(part => char.ToUpperInvariant(part[0]) + part[1..].ToLowerInvariant()))
            };
        }

        [HttpGet]
        public async Task<ActionResult<List<Company>>> GetAll(CancellationToken cancellationToken)
        {
            var userId = CurrentUserId;
            var q = _db.Companies.AsQueryable();
            if (!string.IsNullOrWhiteSpace(userId))
                q = q.Where(c => c.OwnerUserId == userId);

            var companies = await q
                .OrderBy(c => c.Name)
                .ToListAsync(cancellationToken);

            return Ok(companies);
        }

        [HttpGet("{id:int}")]
        public async Task<ActionResult<Company>> GetById([FromRoute] int id, CancellationToken cancellationToken)
        {
            var userId = CurrentUserId;
            var q = _db.Companies.AsQueryable();
            if (!string.IsNullOrWhiteSpace(userId))
                q = q.Where(c => c.OwnerUserId == userId);

            var company = await q.FirstOrDefaultAsync(c => c.Id == id, cancellationToken);
            if (company is null) return NotFound();
            return Ok(company);
        }

        public sealed record CreateCompanyRequest(string Name, string? Location, string? Source);
        public sealed record UpdateCompanyRequest(
            string Name,
            string? Location,
            string? Source,
            string? RecruiterName,
            string? RecruiterEmail,
            string? RecruiterLinkedIn,
            DateTime? LastContactedAt,
            DateTime? NextContactAt,
            string? PipelineStage
        );

        [HttpPost]
        public async Task<ActionResult<Company>> Create([FromBody] CreateCompanyRequest request, CancellationToken cancellationToken)
        {
            var userId = CurrentUserId;
            var name = (request.Name ?? "").Trim();
            if (name.Length == 0) return BadRequest("Company name is required.");

            var existingQuery = _db.Companies.AsQueryable();
            if (!string.IsNullOrWhiteSpace(userId))
                existingQuery = existingQuery.Where(c => c.OwnerUserId == userId);

            var existing = await existingQuery
                .FirstOrDefaultAsync(c => c.Name.ToLower() == name.ToLower(), cancellationToken);

            if (existing is not null)
            {
                // Idempotent create: return existing instead of failing.
                return Ok(existing);
            }

            var company = new Company
            {
                OwnerUserId = string.IsNullOrWhiteSpace(userId) ? null : userId,
                Name = name,
                Location = string.IsNullOrWhiteSpace(request.Location) ? null : request.Location.Trim(),
                Source = NormalizeSource(request.Source),
            };

            _db.Companies.Add(company);
            await _db.SaveChangesAsync(cancellationToken);

            return CreatedAtAction(nameof(GetById), new { id = company.Id }, company);
        }

        [HttpPut("{id:int}")]
        public async Task<ActionResult<Company>> Update([FromRoute] int id, [FromBody] UpdateCompanyRequest request, CancellationToken cancellationToken)
        {
            var userId = CurrentUserId;
            var q = _db.Companies.AsQueryable();
            if (!string.IsNullOrWhiteSpace(userId))
                q = q.Where(c => c.OwnerUserId == userId);

            var company = await q.FirstOrDefaultAsync(c => c.Id == id, cancellationToken);
            if (company is null) return NotFound();

            var name = (request.Name ?? "").Trim();
            if (name.Length == 0) return BadRequest("Company name is required.");

            company.Name = name;
            company.Location = string.IsNullOrWhiteSpace(request.Location) ? null : request.Location.Trim();
            company.Source = NormalizeSource(request.Source);

            company.RecruiterName = string.IsNullOrWhiteSpace(request.RecruiterName) ? null : request.RecruiterName.Trim();
            company.RecruiterEmail = string.IsNullOrWhiteSpace(request.RecruiterEmail) ? null : request.RecruiterEmail.Trim();
            company.RecruiterLinkedIn = string.IsNullOrWhiteSpace(request.RecruiterLinkedIn) ? null : request.RecruiterLinkedIn.Trim();
            company.PipelineStage = string.IsNullOrWhiteSpace(request.PipelineStage) ? null : request.PipelineStage.Trim();
            company.LastContactedAt = request.LastContactedAt;
            company.NextContactAt = request.NextContactAt;

            await _db.SaveChangesAsync(cancellationToken);
            return Ok(company);
        }
    }
}
