using System;
using System.ComponentModel;
using System.Xml.Serialization;
using Barotrauma.LuaCs.Data;

namespace Barotrauma;

[Serializable]
public sealed class RunConfig : IRunConfig
{
    /// <summary>
    /// How should scripts be run on the server.
    /// </summary>
    [XmlElement(ElementName = "Server")] 
    [DefaultValue("Standard")]
    public string Server { get; set; }

    /// <summary>
    /// How should scripts be run on the client. 
    /// </summary>
    [XmlElement(ElementName = "Client")] 
    [DefaultValue("Standard")]
    public string Client { get; set; }

    /// <summary>
    /// List of dependencies by either Steam Workshop ID or by Partial Inclusive Name (ie. "ModDep" will match a mod named "A ModDependency").
    /// PIN Dependency checks if ContentPackage names contains the dependency string.
    /// </summary>
    [XmlArrayItem(ElementName = "Dependency", IsNullable = true, Type = typeof(Dependency))]
    [XmlArray]
    public Dependency[] Dependencies { get; set; }
    
    /// <summary>
    /// Compiles the mod using non-publicized assemblies.
    /// </summary>
    [XmlElement(ElementName = "UseNonPublicizedAssemblies")]
    public bool UseNonPublicizedAssemblies { get; set; }
    
    /// <summary>
    /// If the mod includes source files, the compiled assembly will be named "CompiledAssembly" and have the [InternalVisibleTo()] attribute applied to it.
    /// </summary>
    [XmlElement(ElementName = "UseInternalAssemblyName")]
    [DefaultValue(false)]
    public bool UseInternalAssemblyName { get; set; }
    
    [XmlElement(ElementName = "AutoGenerated")]
    public bool AutoGenerated { get; set; }

    public RunConfig(bool autoGenerated)
    {
        this.AutoGenerated = autoGenerated;
        if (autoGenerated)
        {
            (Client, Server) = ("Standard", "Standard");
            UseNonPublicizedAssemblies = false;
        }
    }

    public RunConfig() { }  // For serialization use
    
    [Serializable]
    public sealed class Dependency
    {
        /// <summary>
        /// Steam Workshop ID of the dependency.
        /// </summary>
        [XmlElement(ElementName = "SteamWorkshopId")]
        public ulong SteamWorkshopId;

        /// <summary>
        /// Package Name of the dependency. Not needed if SteamWorkshopId is set.
        /// </summary>
        [XmlElement(ElementName = "PackageName")]
        public string PackageName;
    }

    public RunConfig Sanitize()
    {
        try
        {
            Client = SanitizeRunSetting(Client);
        }
        catch (Exception)
        {
            Client = "Standard";
        }

        try
        {
            Server = SanitizeRunSetting(Server);
        }
        catch (Exception)
        {
            Server = "Standard";
        }
        
        Dependencies ??= new RunConfig.Dependency[] { };

        static string SanitizeRunSetting(string str) =>
            str switch
            {
                null => "Standard",
                "" => "Standard",
                " " => "Standard",
                _ => str[0].ToString().ToUpper() + str.Substring(1).ToLower()
            };

        return this;
    }

    public bool IsForced()
    {
#if CLIENT
        return this.Client == "Forced";
#elif SERVER
        return this.Server == "Forced";
#endif
    }
    
    public bool IsStandard()
    {
#if CLIENT
        return this.Client == "Standard";
#elif SERVER
        return this.Server == "Standard";
#endif
    }

    public bool IsForcedOrStandard() => this.IsForced() || this.IsStandard();

}
