namespace LeetCode.Logic;

public class MaxSubArrayInts
{
    public (int maxSum, int[]? array, string errors) MaxSubArray(int[]? nums)
    {
        if (nums is null || nums.Length == 0)
        {
            return (0, null, "Input array is null or empty");
        }
        
        var result = nums
            .Skip(1)
            .Aggregate(
                // accumulator:
                (
                    currentSum: nums[0],
                    currentList: new List<int> { nums[0] },
                    maxSum: nums[0],
                    maxList: new List<int> { nums[0] }
                ),
                (acc, num) =>
                {
                    if (!int.TryParse(num.ToString(), out _)) throw new ArgumentException("Only integers are allowed in the input array");
                    
                    // Decide: extend or restart
                    if (acc.currentSum + num < num)
                    {
                        acc.currentSum = num;
                        acc.currentList = [num];
                    }
                    else
                    {
                        acc.currentSum += num;
                        acc.currentList.Add(num);
                    }

                    // Update max if needed
                    if (acc.currentSum > acc.maxSum)
                    {
                        acc.maxSum = acc.currentSum;
                        acc.maxList = [..acc.currentList];
                    }

                    return acc;
                }
            );
        
        return (result.maxSum, result.maxList.ToArray(), string.Empty);
    }

    public (int maxSum, int[]? array, string errors) MaxSubArray2(int[]? nums)
    {
        var numSize = nums?.Length ?? 0; // if zero return immediately 
        
        if (numSize == 0) return (0, null, "Input array is null or empty");

        var firstElement = nums![0];
        var maxSum = firstElement; // assume the first element is the max
        var currentMax = firstElement;
        int start = 0, end = 0, tempStart = 0;

        for (var i = 1; i < numSize; i++)
        {
            // If the current element is greater than the running sum + current element,
            // it's better to start a new subarray from the current element.
            var currentElement = nums[i];
            if (currentElement > currentMax + currentElement)
            {
                currentMax = currentElement;
                tempStart = i;
            }
            else
            {
                currentMax += currentElement;
            }
            
            // If our current running sum is the best we've seen, update the global max.
            if (currentMax > maxSum)
            {
                maxSum = currentMax;
                start = tempStart;
                end = i;
            }
        }

        var result = new int[end - start + 1];
        Array.Copy(nums, start, 
            result, 0, 
            result.Length);

        return (maxSum, result, string.Empty);
    }
    
    public int MaxSubArraySumOnly(int[] nums)
    {
        var numSize = nums?.Length ?? 0;
        
        if (numSize == 0) return 0;
        
        var maxSum = nums![0]; // assume the first element is the max
        var currentMax = nums[0];

        for (var i = 1; i < numSize; i++)
        {
            var currentElement = nums[i];
            // Either extend the previous subarray or start a new one at the current element
            currentMax = Math.Max(currentElement, currentMax + currentElement);
                
            // Keep track of the highest sum seen so far
            maxSum = Math.Max(maxSum, currentMax);
        }

        return maxSum;
    }

}