using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PSO2SERVER.Models
{
    public struct Duration : IEquatable<Duration>, IComparable<Duration>
    {
        // The number of seconds in the duration
        public long Seconds { get; }

        // The number of nanoseconds, should always be between 0 and 999,999,999
        public int Nanoseconds { get; }

        // Constructor to initialize a Duration with seconds and nanoseconds
        public Duration(long seconds, int nanoseconds)
        {
            if (nanoseconds < 0 || nanoseconds >= 1_000_000_000)
            {
                throw new ArgumentOutOfRangeException(nameof(nanoseconds), "Nanoseconds must be between 0 and 999,999,999.");
            }

            Seconds = seconds;
            Nanoseconds = nanoseconds;
        }

        // A default zero-length duration
        public static Duration Zero => new Duration(0, 0);

        // Adds two durations together
        public static Duration operator +(Duration left, Duration right)
        {
            long totalSeconds = left.Seconds + right.Seconds;
            int totalNanoseconds = left.Nanoseconds + right.Nanoseconds;

            // Handle carry over for nanoseconds
            if (totalNanoseconds >= 1_000_000_000)
            {
                totalSeconds++;
                totalNanoseconds -= 1_000_000_000;
            }

            return new Duration(totalSeconds, totalNanoseconds);
        }

        // Subtracts one duration from another
        public static Duration operator -(Duration left, Duration right)
        {
            long totalSeconds = left.Seconds - right.Seconds;
            int totalNanoseconds = left.Nanoseconds - right.Nanoseconds;

            // Handle borrow for nanoseconds
            if (totalNanoseconds < 0)
            {
                totalSeconds--;
                totalNanoseconds += 1_000_000_000;
            }

            return new Duration(totalSeconds, totalNanoseconds);
        }

        // Compare two durations
        public int CompareTo(Duration other)
        {
            if (Seconds < other.Seconds) return -1;
            if (Seconds > other.Seconds) return 1;

            return Nanoseconds.CompareTo(other.Nanoseconds);
        }

        // Check if two durations are equal
        public bool Equals(Duration other)
        {
            return Seconds == other.Seconds && Nanoseconds == other.Nanoseconds;
        }

        // Override ToString() for custom string representation
        public override string ToString()
        {
            return $"{Seconds}s {Nanoseconds}ns";
        }

        // Static method to create a Duration from milliseconds
        public static Duration FromMilliseconds(long milliseconds)
        {
            long seconds = milliseconds / 1000;
            int nanoseconds = (int)((milliseconds % 1000) * 1_000_000);
            return new Duration(seconds, nanoseconds);
        }

        // Static method to create a Duration from seconds and nanoseconds
        public static Duration FromSeconds(long seconds, int nanoseconds)
        {
            return new Duration(seconds, nanoseconds);
        }
    }

}
