using RandomNameGeneratorLibrary;

namespace CrestronOpenCvSharp.Capture;

public class MjpegCapture
{
    private readonly HttpClient _client = new HttpClient();
    private readonly string? _mjpegUrl;
    private readonly string? _directory;
    private readonly FacialRecognition? _facialRecognition;
    private Timer? _timer;
    private readonly PersonNameGenerator _personNameGenerator;

    public bool CaptureRunning { get; private set; }
    
    public MjpegCapture(string? url, string? directory, FacialRecognition? facialRecognition)
    {
        _mjpegUrl = url;
        _directory = Path.Combine(directory!, "captures");
        _facialRecognition = facialRecognition;
        
        _personNameGenerator = new PersonNameGenerator();
    }

    public void StartCapture(int timeout)
    {
        if (string.IsNullOrEmpty(_directory))
        {
            Console.WriteLine("Directory variable was null or empty.");
            CaptureRunning = false;
            return;
        }
        CheckIfDirectoryExists(_directory);
        // Only create if it's null
        _timer = new Timer(CaptureImage, null, 0, timeout);
        CaptureRunning = true;
    }

    public void StopCapture()
    {
        if (_timer is not null)
        {
            // Stop the timer
            _timer.Change(Timeout.Infinite, Timeout.Infinite);
            // Dispose it
            _timer.Dispose();
        }
        CaptureRunning = false;
    }

    private void CheckIfDirectoryExists(string directory)
    {
        Console.WriteLine($"Checking if directory {directory} exists.");
        if (Directory.Exists(directory))
        {
            // Remove the directory and all its contents
            Directory.Delete(directory, true);
            Console.WriteLine($"Directory '{directory}' and all its contents have been removed.");
            Directory.CreateDirectory(directory);
            Console.WriteLine($"Directory '{directory}' has been created.");
        }
        else
        {
            // Create the directory
            Directory.CreateDirectory(directory);
            Console.WriteLine($"Directory '{directory}' has been created.");
        }
    }
    
    private async void CaptureImage(object? state)
    {
        try
        {
            CaptureRunning = true;
            var fileName = Path.Combine(_directory!, $"frame_{DateTime.Now:yyyyMMdd_HHmmss}.jpg");
            try
            {
                HttpResponseMessage response = await _client.GetAsync(_mjpegUrl, HttpCompletionOption.ResponseHeadersRead);
                response.EnsureSuccessStatusCode();

                await using (var stream = await response.Content.ReadAsStreamAsync())
                await using (var fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    await stream.CopyToAsync(fileStream);
                }

                Console.WriteLine($"Saved frame to {fileName}");
                // TODO Send to image preview window on touchpanel
                
                if (_facialRecognition!.CheckForFace(fileName))
                {
                    StopCapture();
                    Console.WriteLine("Face detected, stopping capture");    
                    // TODO Send image to preview window on touchpanel
                    
                    //Path.Combine(_baseDirectory, "aligned.png"));
                    
                    Console.WriteLine("Comparing captured face against database");
                    var result  = await _facialRecognition.CompareFaces();
                    if (result is not null)
                    {
                        Console.WriteLine($"We have found a match! The person in front of the camera is: {result}");
                    }
                    else
                    {
                        Console.WriteLine("No match was found in our database, let's add this person!");
                        var randomFullName = _personNameGenerator.GenerateRandomFirstAndLastName();
                        _facialRecognition.AddPersonToDatabase(randomFullName);
                        Thread.Sleep(2000);
                        Console.WriteLine("Person added to database, restarting capture");
                        StartCapture(2000);
                    }
                }
                else
                {
                    Console.WriteLine("No face detected, carrying on!");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error capturing image: {ex.Message}");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine($"Error capturing image: {e}");
        }
    }
}