using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.Extensions;
/// 
/// Provides extension methods for  to parse 's.
/// 
public static class XmlReaderExtensions
{
    /// 
    /// Reads a trimmed string from the current node.
    /// 
    /// The .
    /// The trimmed content.
    public static string ReadNormalizedString(this XmlReader reader)
    {
        ArgumentNullException.ThrowIfNull(reader);
        return reader.ReadElementContentAsString().Trim();
    }
    /// 
    /// Reads an int from the current node.
    /// 
    /// The .
    /// The parsed int.
    /// A value indicating whether the parsing succeeded.
    public static bool TryReadInt(this XmlReader reader, out int value)
    {
        ArgumentNullException.ThrowIfNull(reader);
        return int.TryParse(reader.ReadElementContentAsString(), CultureInfo.InvariantCulture, out value);
    }
    /// 
    /// Parses a  from the current node.
    /// 
    /// The .
    /// The parsed .
    /// A value indicating whether the parsing succeeded.
    public static bool TryReadDateTime(this XmlReader reader, out DateTime value)
    {
        ArgumentNullException.ThrowIfNull(reader);
        return DateTime.TryParse(
            reader.ReadElementContentAsString(),
            CultureInfo.InvariantCulture,
            DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
            out value);
    }
    /// 
    /// Parses a  from the current node.
    /// 
    /// The .
    /// The date format string.
    /// The parsed .
    /// A value indicating whether the parsing succeeded.
    public static bool TryReadDateTimeExact(this XmlReader reader, string formatString, out DateTime value)
    {
        ArgumentNullException.ThrowIfNull(reader);
        ArgumentNullException.ThrowIfNull(formatString);
        return DateTime.TryParseExact(
            reader.ReadElementContentAsString(),
            formatString,
            CultureInfo.InvariantCulture,
            DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
            out value);
    }
    /// 
    /// Parses a  from the xml node.
    /// 
    /// The .
    /// A , or null if none is found.
    public static PersonInfo? GetPersonFromXmlNode(this XmlReader reader)
    {
        ArgumentNullException.ThrowIfNull(reader);
        if (reader.IsEmptyElement)
        {
            reader.Read();
            return null;
        }
        var name = string.Empty;
        var type = PersonKind.Actor;  // If type is not specified assume actor
        var role = string.Empty;
        int? sortOrder = null;
        string? imageUrl = null;
        using var subtree = reader.ReadSubtree();
        subtree.MoveToContent();
        subtree.Read();
        while (subtree is { EOF: false, ReadState: ReadState.Interactive })
        {
            if (subtree.NodeType != XmlNodeType.Element)
            {
                subtree.Read();
                continue;
            }
            switch (subtree.Name)
            {
                case "name":
                case "Name":
                    name = subtree.ReadNormalizedString();
                    break;
                case "role":
                case "Role":
                    role = subtree.ReadNormalizedString();
                    break;
                case "type":
                case "Type":
                    Enum.TryParse(subtree.ReadElementContentAsString(), true, out type);
                    break;
                case "order":
                case "sortorder":
                case "SortOrder":
                    if (subtree.TryReadInt(out var sortOrderVal))
                    {
                        sortOrder = sortOrderVal;
                    }
                    break;
                case "thumb":
                    imageUrl = subtree.ReadNormalizedString();
                    break;
                default:
                    subtree.Skip();
                    break;
            }
        }
        if (string.IsNullOrWhiteSpace(name))
        {
            return null;
        }
        return new PersonInfo
        {
            Name = name,
            Role = role,
            Type = type,
            SortOrder = sortOrder,
            ImageUrl = imageUrl
        };
    }
    /// 
    /// Used to split names of comma or pipe delimited genres and people.
    /// 
    /// The .
    /// IEnumerable{System.String}.
    public static IEnumerable GetStringArray(this XmlReader reader)
    {
        ArgumentNullException.ThrowIfNull(reader);
        var value = reader.ReadElementContentAsString();
        // Only split by comma if there is no pipe in the string
        // We have to be careful to not split names like Matthew, Jr.
        var separator = !value.Contains('|', StringComparison.Ordinal)
            && !value.Contains(';', StringComparison.Ordinal)
                ? new[] { ',' }
                : new[] { '|', ';' };
        foreach (var part in value.Trim().Trim(separator).Split(separator))
        {
            if (!string.IsNullOrWhiteSpace(part))
            {
                yield return part.Trim();
            }
        }
    }
    /// 
    /// Parses a  array from the xml node.
    /// 
    /// The .
    /// The .
    /// The .
    public static IEnumerable GetPersonArray(this XmlReader reader, PersonKind personKind)
        => reader.GetStringArray()
            .Select(part => new PersonInfo { Name = part, Type = personKind });
}