using Microsoft.AspNetCore.Mvc;
using PlaylistShared.Models;
using System.Net.Http.Headers;
using System.Text.Json;

namespace PlaylistShared.Controllers;

[Microsoft.AspNetCore.Mvc.Route("auth")]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly IConfiguration _config;
    private readonly HttpClient _httpClient;
    private readonly AppDbContext _db;
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly ILogger<AuthController> _logger;

    public AuthController(
        IConfiguration config,
        IHttpClientFactory factory,
        AppDbContext db,
        SignInManager<ApplicationUser> signInManager,
        ILogger<AuthController> logger)
    {
        _config = config;
        _httpClient = factory.CreateClient();
        _db = db;
        _signInManager = signInManager;
        _logger = logger;
    }

    [HttpGet("login")]
    public IActionResult Login()
    {
        var clientId = _config["YandexOAuth:ClientId"];
        var redirectUri = Url.Action(nameof(Callback), "Auth", null, Request.Scheme);
        var authUrl = $"{_config["YandexOAuth:AuthorizationEndpoint"]}?response_type=code&client_id={clientId}&redirect_uri={Uri.EscapeDataString(redirectUri!)}";
        return Redirect(authUrl);
    }

    [HttpGet("callback")]
    public async Task<IActionResult> Callback(string code)
    {
        if (string.IsNullOrEmpty(code))
            return BadRequest("Missing code");

        var tokenResponse = await ExchangeCodeForTokenAsync(code);
        if (tokenResponse is null)
            return StatusCode(500, "Token exchange failed");

        var userInfo = await GetUserInfoAsync(tokenResponse.AccessToken);
        if (userInfo is null)
            return StatusCode(500, "User info fetch failed");

        var user = await _db.Users.FirstOrDefaultAsync(u => u.YandexId == userInfo.Id);
        if (user is null)
        {
            user = new ApplicationUser
            {
                UserName = userInfo.Login,
                YandexId = userInfo.Id,
                Email = userInfo.DefaultEmail,
                AccessToken = tokenResponse.AccessToken,
                RefreshToken = tokenResponse.RefreshToken,
                AccessTokenExpiresAt = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn)
            };
            _db.Users.Add(user);
        }
        else
        {
            user.AccessToken = tokenResponse.AccessToken;
            user.RefreshToken = tokenResponse.RefreshToken;
            user.AccessTokenExpiresAt = DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn);
            _db.Users.Update(user);
        }
        await _db.SaveChangesAsync();

        await _signInManager.SignInAsync(user, isPersistent: false);
        return Redirect("/");
    }

    private async Task<YandexTokenResponse?> ExchangeCodeForTokenAsync(string code)
    {
        var tokenUrl = _config["YandexOAuth:TokenEndpoint"];
        var redirectUri = Url.Action(nameof(Callback), "Auth", null, Request.Scheme);
        var content = new FormUrlEncodedContent(new[]
        {
            new KeyValuePair<string, string>("grant_type", "authorization_code"),
            new KeyValuePair<string, string>("code", code),
            new KeyValuePair<string, string>("client_id", _config["YandexOAuth:ClientId"]!),
            new KeyValuePair<string, string>("client_secret", _config["YandexOAuth:ClientSecret"]!),
            new KeyValuePair<string, string>("redirect_uri", redirectUri!)
        });

        var response = await _httpClient.PostAsync(tokenUrl!, content);
        if (!response.IsSuccessStatusCode) return null;
        var json = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<YandexTokenResponse>(json);
    }

    private async Task<YandexUserInfo?> GetUserInfoAsync(string accessToken)
    {
        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("OAuth", accessToken);
        var response = await _httpClient.GetAsync(_config["YandexOAuth:UserInfoEndpoint"]!);
        if (!response.IsSuccessStatusCode) return null;
        var json = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<YandexUserInfo>(json);
    }
}