using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using ytLive.Models;

namespace ytLive.Services;

/// <summary>
/// Manages YouTube live stream lifecycle — create broadcasts,
/// bind stream keys, monitor health.
/// </summary>
public class YouTubeStreamService
{
    private readonly YouTubeAuthService _auth;
    private readonly HttpClient _http;
    private const string ApiBase = "https://www.googleapis.com/youtube/v3";

    public YouTubeStreamService(YouTubeAuthService auth, HttpClient? http = null)
    {
        _auth = auth;
        _http = http ?? new HttpClient();
    }

    private async Task<bool> EnsureToken()
    {
        if (_auth.CurrentChannel == null) return false;
        if (_auth.CurrentChannel.TokenExpiry <= DateTime.UtcNow.AddMinutes(5))
            return await _auth.RefreshToken();
        return true;
    }

    public async Task<string?> CreateBroadcast(string title, string description, DateTime scheduledStartTime)
    {
        if (!await EnsureToken()) return null;

        var broadcast = new
        {
            snippet = new
            {
                title,
                description,
                scheduledStartTime = scheduledStartTime.ToString("o"),
                categoryId = "22"  // People & Blogs
            },
            status = new
            {
                // Private-only by enforcement (ship step 7) — the Go Live dialog
                // is locked to Private and the service refuses anything else.
                privacyStatus = "private",
                selfDeclaredMadeForKids = false
            },
            contentDetails = new
            {
                enableAutoStart = true,
                enableAutoStop = true
            }
        };

        _http.DefaultRequestHeaders.Authorization = new("Bearer", _auth.CurrentChannel!.AccessToken);
        var response = await _http.PostAsJsonAsync(
            $"{ApiBase}/liveBroadcasts?part=snippet,status,contentDetails", broadcast);

        if (!response.IsSuccessStatusCode) return null;

        var json = await response.Content.ReadAsStringAsync();
        var data = JsonSerializer.Deserialize<JsonElement>(json);
        return data.GetProperty("id").GetString();
    }

    public async Task<string?> BindStream(string broadcastId, string streamKey)
    {
        if (!await EnsureToken()) return null;

        // Create stream resource
        var stream = new
        {
            snippet = new { title = $"stream-{broadcastId}" },
            contentDetails = new
            {
                ingestionType = "rtmp",
                frameRate = "60fps",
                resolution = "1080p"
            }
        };

        _http.DefaultRequestHeaders.Authorization = new("Bearer", _auth.CurrentChannel!.AccessToken);
        var response = await _http.PostAsJsonAsync(
            $"{ApiBase}/liveStreams?part=snippet,contentDetails", stream);

        if (!response.IsSuccessStatusCode) return null;

        var json = await response.Content.ReadAsStringAsync();
        var data = JsonSerializer.Deserialize<JsonElement>(json);
        var streamId = data.GetProperty("id").GetString();

        // Bind stream to broadcast
        var bindResponse = await _http.PutAsJsonAsync(
            $"{ApiBase}/liveBroadcasts?part=id,contentDetails&id={broadcastId}",
            new { contentDetails = new { streamId } });

        return bindResponse.IsSuccessStatusCode ? streamId : null;
    }

    public async Task<StreamHealth?> GetStreamHealth(string broadcastId)
    {
        if (!await EnsureToken()) return null;

        _http.DefaultRequestHeaders.Authorization = new("Bearer", _auth.CurrentChannel!.AccessToken);
        var response = await _http.GetAsync(
            $"{ApiBase}/liveBroadcasts?part=contentDetails,status&id={broadcastId}");

        if (!response.IsSuccessStatusCode) return null;

        var json = await response.Content.ReadAsStringAsync();
        var data = JsonSerializer.Deserialize<JsonElement>(json);
        var items = data.GetProperty("items");
        if (items.GetArrayLength() == 0) return null;

        var status = items[0].GetProperty("status").GetProperty("lifeCycleStatus").GetString();
        return new StreamHealth
        {
            HealthStatus = status switch
            {
                "live" => "good",
                "ready" => "ok",
                "created" => "ok",
                _ => "bad"
            },
            HealthMessage = status
        };
    }
}
