namespace Sbroenne.ExcelMcp.Generators.Common;

/// <summary>
/// Extracted service information from an interface marked with [ServiceCategory].
/// </summary>
public sealed class ServiceInfo
{
    public string Category { get; }
    public string CategoryPascal { get; }
    public string McpToolName { get; }
    public bool NoSession { get; }
    public string? XmlDocSummary { get; }
    public List<MethodInfo> Methods { get; }

    /// <summary>Human-readable title for the MCP tool (e.g., "Excel Power Query Operations").</summary>
    public string? McpToolTitle { get; }

    /// <summary>Whether the tool is destructive (modifies data). Default: true.</summary>
    public bool McpToolDestructive { get; }

    /// <summary>MCP meta category (e.g., "data", "analysis", "query").</summary>
    public string? McpToolCategory { get; }

    /// <summary>Tool description for LLMs via [Description], since XML docs aren't available from metadata refs.</summary>
    public string? McpToolDescription { get; }

    /// <summary>Whether the interface has an explicit [McpTool] attribute. Used by MCP generator to skip hand-written tools.</summary>
    public bool HasMcpToolAttribute { get; }

    public ServiceInfo(string category, string categoryPascal, string mcpToolName, bool noSession, List<MethodInfo> methods,
        string? xmlDocSummary = null, string? mcpToolTitle = null, bool mcpToolDestructive = true, string? mcpToolCategory = null,
        string? mcpToolDescription = null, bool hasMcpToolAttribute = true)
    {
        Category = category;
        CategoryPascal = categoryPascal;
        McpToolName = mcpToolName;
        NoSession = noSession;
        XmlDocSummary = xmlDocSummary;
        Methods = methods;
        McpToolTitle = mcpToolTitle;
        McpToolDestructive = mcpToolDestructive;
        McpToolCategory = mcpToolCategory;
        McpToolDescription = mcpToolDescription;
        HasMcpToolAttribute = hasMcpToolAttribute;
    }
}

/// <summary>
/// Extracted method information from interface method.
/// </summary>
public sealed class MethodInfo
{
    public string MethodName { get; }
    public string ActionName { get; }
    public string ReturnType { get; }
    public string McpTool { get; }
    public List<ParameterInfo> Parameters { get; }
    public string? XmlDocSummary { get; }
    /// <summary>Whether the original interface method has an IExcelBatch parameter.</summary>
    public bool HasBatchParameter { get; }

    /// <summary>Whether the original interface method has an IProgress&lt;T&gt; parameter.</summary>
    public bool HasProgressParameter { get; }

    public MethodInfo(string methodName, string actionName, string returnType, string mcpTool,
        List<ParameterInfo> parameters, string? xmlDocSummary = null, bool hasBatchParameter = true,
        bool hasProgressParameter = false)
    {
        MethodName = methodName;
        ActionName = actionName;
        ReturnType = returnType;
        McpTool = mcpTool;
        Parameters = parameters;
        XmlDocSummary = xmlDocSummary;
        HasBatchParameter = hasBatchParameter;
        HasProgressParameter = hasProgressParameter;
    }
}

/// <summary>
/// Extracted parameter information.
/// </summary>
public sealed class ParameterInfo
{
    public string Name { get; }
    public string TypeName { get; }
    public bool HasDefault { get; }
    public string? DefaultValue { get; }
    public bool IsFileOrValue { get; }
    public string? FileSuffix { get; }
    public bool IsFromString { get; }
    public string? ExposedName { get; }
    public bool IsRequired { get; }
    public bool IsEnum { get; }
    public string? XmlDocDescription { get; }

    /// <summary>
    /// The fully qualified enum type name when IsFromString and IsEnum are both true.
    /// Used by MCP generator to emit typed enum parameters instead of strings.
    /// </summary>
    public string? EnumTypeName { get; }

    public ParameterInfo(string name, string typeName, bool hasDefault, string? defaultValue,
        bool isFileOrValue = false, string? fileSuffix = null,
        bool isFromString = false, string? exposedName = null,
        bool isRequired = false, bool isEnum = false,
        string? xmlDocDescription = null, string? enumTypeName = null)
    {
        Name = name;
        TypeName = typeName;
        HasDefault = hasDefault;
        DefaultValue = defaultValue;
        IsFileOrValue = isFileOrValue;
        FileSuffix = fileSuffix;
        IsFromString = isFromString;
        ExposedName = exposedName;
        IsRequired = isRequired;
        IsEnum = isEnum;
        XmlDocDescription = xmlDocDescription;
        EnumTypeName = enumTypeName;
    }
}

/// <summary>
/// Exposed parameter (aggregated across methods for CLI/MCP Settings).
/// </summary>
public sealed class ExposedParameter
{
    public string Name { get; }
    public string TypeName { get; set; }
    public string? Description { get; }
    public string? DefaultValue { get; }

    /// <summary>Action names where this parameter is required (non-nullable, no default, or [RequiredParameter]).</summary>
    public List<string> RequiredByActions { get; } = new();

    /// <summary>Total number of actions in the service (for computing "required for all" vs subset).</summary>
    public int TotalActionCount { get; set; }

    public ExposedParameter(string name, string typeName, string? description = null, string? defaultValue = null)
    {
        Name = name;
        TypeName = typeName;
        Description = description;
        DefaultValue = defaultValue;
    }

    /// <summary>
    /// Returns the description with required-by-actions suffix appended.
    /// E.g., "Name of the PivotTable (required for: read, delete, refresh)"
    /// or "Name of the PivotTable (required)" if required for all actions.
    /// </summary>
    public string? DescriptionWithRequired
    {
        get
        {
            if (RequiredByActions.Count == 0)
                return Description;

            var suffix = RequiredByActions.Count == TotalActionCount
                ? "(required)"
                : $"(required for: {string.Join(", ", RequiredByActions)})";

            return string.IsNullOrEmpty(Description)
                ? suffix
                : $"{Description} {suffix}";
        }
    }
}
