using System.Diagnostics.CodeAnalysis;
using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Scheduling.Engine;
using IronPython.Runtime;

namespace ErsatzTV.Core.Scheduling.ScriptedScheduling.Modules;

[SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores")]
[SuppressMessage("Usage", "VSTHRD002:Avoid problematic synchronous waits")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public class PlayoutModule(ISchedulingEngine schedulingEngine, CancellationToken cancellationToken)
{
    public int FailureCount { get; private set; }

    // content instructions

    public void add_all(
        string content,
        string filler_kind = null,
        string custom_title = null,
        bool disable_watermarks = false)
    {
        Option<FillerKind> maybeFillerKind = Option<FillerKind>.None;
        if (Enum.TryParse(filler_kind, ignoreCase: true, out FillerKind fillerKind))
        {
            maybeFillerKind = fillerKind;
        }

        bool success = schedulingEngine.AddAll(content, maybeFillerKind, custom_title, disable_watermarks);
        if (success)
        {
            FailureCount = 0;
        }
        else
        {
            FailureCount++;
        }
    }

    public void add_count(
        string content,
        int count,
        string filler_kind = null,
        string custom_title = null,
        bool disable_watermarks = false)
    {
        Option<FillerKind> maybeFillerKind = Option<FillerKind>.None;
        if (Enum.TryParse(filler_kind, ignoreCase: true, out FillerKind fillerKind))
        {
            maybeFillerKind = fillerKind;
        }

        bool success = schedulingEngine.AddCount(content, count, maybeFillerKind, custom_title, disable_watermarks);
        if (success)
        {
            FailureCount = 0;
        }
        else
        {
            FailureCount++;
        }
    }

    public void add_duration(
        string content,
        string duration,
        string fallback = null,
        bool trim = false,
        int discard_attempts = 0,
        bool stop_before_end = true,
        bool offline_tail = false,
        string filler_kind = null,
        string custom_title = null,
        bool disable_watermarks = false)
    {
        Option<FillerKind> maybeFillerKind = Option<FillerKind>.None;
        if (Enum.TryParse(filler_kind, ignoreCase: true, out FillerKind fillerKind))
        {
            maybeFillerKind = fillerKind;
        }

        bool success = schedulingEngine.AddDuration(
            content,
            duration,
            fallback,
            trim,
            discard_attempts,
            stop_before_end,
            offline_tail,
            maybeFillerKind,
            custom_title,
            disable_watermarks);

        if (success)
        {
            FailureCount = 0;
        }
        else
        {
            FailureCount++;
        }
    }

    public void pad_to_next(
        string content,
        int minutes,
        string fallback = null,
        bool trim = false,
        int discard_attempts = 0,
        bool stop_before_end = true,
        bool offline_tail = true,
        string filler_kind = null,
        string custom_title = null,
        bool disable_watermarks = false)
    {
        Option<FillerKind> maybeFillerKind = Option<FillerKind>.None;
        if (Enum.TryParse(filler_kind, ignoreCase: true, out FillerKind fillerKind))
        {
            maybeFillerKind = fillerKind;
        }

        bool success = schedulingEngine.PadToNext(
            content,
            minutes,
            fallback,
            trim,
            discard_attempts,
            stop_before_end,
            offline_tail,
            maybeFillerKind,
            custom_title,
            disable_watermarks);

        if (success)
        {
            FailureCount = 0;
        }
        else
        {
            FailureCount++;
        }
    }

    public void pad_until(
        string content,
        string when,
        bool tomorrow = false,
        string fallback = null,
        bool trim = false,
        int discard_attempts = 0,
        bool stop_before_end = true,
        bool offline_tail = false,
        string filler_kind = null,
        string custom_title = null,
        bool disable_watermarks = false)
    {
        Option<FillerKind> maybeFillerKind = Option<FillerKind>.None;
        if (Enum.TryParse(filler_kind, ignoreCase: true, out FillerKind fillerKind))
        {
            maybeFillerKind = fillerKind;
        }

        bool success = schedulingEngine.PadUntil(
            content,
            when,
            tomorrow,
            fallback,
            trim,
            discard_attempts,
            stop_before_end,
            offline_tail,
            maybeFillerKind,
            custom_title,
            disable_watermarks);

        if (success)
        {
            FailureCount = 0;
        }
        else
        {
            FailureCount++;
        }
    }


    // control instructions

    public void start_epg_group(bool advance = true)
    {
        schedulingEngine.LockGuideGroup(advance);
    }

    public void stop_epg_group()
    {
        schedulingEngine.UnlockGuideGroup();
    }

    public void graphics_on(string graphics, PythonDictionary variables = null)
    {
        var maybeVariables = new Dictionary<string, string>();
        if (variables != null)
        {
            maybeVariables = variables.ToDictionary(v => v.Key.ToString(), v => v.Value.ToString());
        }

        schedulingEngine
            .GraphicsOn([graphics], maybeVariables, cancellationToken)
            .GetAwaiter()
            .GetResult();
    }

    public void graphics_on(PythonList graphics, PythonDictionary variables = null)
    {
        var maybeVariables = new Dictionary<string, string>();
        if (variables != null)
        {
            maybeVariables = variables.ToDictionary(v => v.Key.ToString(), v => v.Value.ToString());
        }

        schedulingEngine
            .GraphicsOn(
                graphics.Select(g => g.ToString()).ToList(),
                maybeVariables,
                cancellationToken)
            .GetAwaiter()
            .GetResult();
    }

    public void graphics_off(string graphics = null)
    {
        if (string.IsNullOrWhiteSpace(graphics))
        {
            schedulingEngine.GraphicsOff([], cancellationToken).GetAwaiter().GetResult();
        }
        else
        {
            schedulingEngine.GraphicsOff([graphics], cancellationToken).GetAwaiter().GetResult();
        }
    }

    public void graphics_off(PythonList graphics)
    {
        schedulingEngine
            .GraphicsOff(graphics.Select(g => g.ToString()).ToList(), cancellationToken)
            .GetAwaiter()
            .GetResult();
    }

    public void watermark_on(string watermark)
    {
        schedulingEngine.WatermarkOn([watermark]).GetAwaiter().GetResult();
    }

    public void watermark_on(PythonList watermark)
    {
        schedulingEngine
            .WatermarkOn(watermark.Select(g => g.ToString()).ToList())
            .GetAwaiter()
            .GetResult();
    }

    public void watermark_off(string watermark = null)
    {
        if (string.IsNullOrWhiteSpace(watermark))
        {
            schedulingEngine.WatermarkOff([]).GetAwaiter().GetResult();
        }
        else
        {
            schedulingEngine.WatermarkOff([watermark]).GetAwaiter().GetResult();
        }
    }

    public void watermark_off(PythonList watermark)
    {
        schedulingEngine.WatermarkOff(watermark.Select(g => g.ToString()).ToList()).GetAwaiter().GetResult();
    }

    public void skip_items(string content, int count)
    {
        schedulingEngine.SkipItems(content, count);
    }

    public void skip_to_item(string content, int season, int episode)
    {
        schedulingEngine.SkipToItem(content, season, episode);
    }

    public void wait_until(string when, bool tomorrow = false, bool rewind_on_reset = false)
    {
        if (TimeOnly.TryParse(when, out TimeOnly waitUntil))
        {
            schedulingEngine.WaitUntil(waitUntil, tomorrow, rewind_on_reset);
        }
    }
}
