// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.npc.asset.builder.validators;

import java.lang.invoke.CallSite;
import java.lang.reflect.UndeclaredThrowableException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.StringConcatFactory;
import java.lang.invoke.MethodType;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.time.Duration;
import java.time.Period;
import java.time.ZoneId;
import com.hypixel.hytale.server.core.modules.time.WorldTimeResource;
import java.time.chrono.ChronoLocalDateTime;
import java.time.LocalDateTime;
import javax.annotation.Nonnull;
import java.time.temporal.TemporalAmount;

public class TemporalSequenceValidator extends TemporalArrayValidator
{
    private final RelationalOperator relationLower;
    private final TemporalAmount lower;
    private final RelationalOperator relationUpper;
    private final TemporalAmount upper;
    private final RelationalOperator relationSequence;
    
    private TemporalSequenceValidator(final RelationalOperator relationLower, final TemporalAmount lower, final RelationalOperator relationUpper, final TemporalAmount upper, final RelationalOperator relationSequence) {
        this.lower = lower;
        this.upper = upper;
        this.relationLower = relationLower;
        this.relationUpper = relationUpper;
        this.relationSequence = relationSequence;
    }
    
    @Nonnull
    public static TemporalSequenceValidator betweenMonotonic(final TemporalAmount lower, final TemporalAmount upper) {
        return new TemporalSequenceValidator(RelationalOperator.GreaterEqual, lower, RelationalOperator.LessEqual, upper, RelationalOperator.Less);
    }
    
    @Nonnull
    public static TemporalSequenceValidator betweenWeaklyMonotonic(final TemporalAmount lower, final TemporalAmount upper) {
        return new TemporalSequenceValidator(RelationalOperator.GreaterEqual, lower, RelationalOperator.LessEqual, upper, RelationalOperator.LessEqual);
    }
    
    public static boolean compare(@Nonnull final LocalDateTime value, @Nonnull final RelationalOperator op, final LocalDateTime c) {
        return switch (op) {
            default -> throw new MatchException(null, null);
            case NotEqual -> !value.equals(c);
            case Less -> value.isBefore(c);
            case LessEqual -> !value.isAfter(c);
            case Greater -> value.isAfter(c);
            case GreaterEqual -> !value.isBefore(c);
            case Equal -> value.equals(c);
        };
    }
    
    @Override
    public boolean test(@Nonnull final TemporalAmount[] values) {
        final LocalDateTime zeroDate = LocalDateTime.ofInstant(WorldTimeResource.ZERO_YEAR, WorldTimeResource.ZONE_OFFSET);
        final LocalDateTime min = zeroDate.plus(this.lower);
        final LocalDateTime max = zeroDate.plus(this.upper);
        final boolean expectPeriod = values[0] instanceof Period;
        for (int i = 0; i < values.length; ++i) {
            final TemporalAmount value = values[i];
            if (value instanceof Period && !expectPeriod) {
                return false;
            }
            if (value instanceof Duration && expectPeriod) {
                return false;
            }
            final LocalDateTime dateValue = zeroDate.plus(values[i]);
            if (!compare(dateValue, this.relationLower, min) && compare(dateValue, this.relationUpper, max)) {
                return false;
            }
            if (i > 0 && this.relationSequence != null) {
                final LocalDateTime previousValue = zeroDate.plus(values[i - 1]);
                if (!compare(previousValue, this.relationSequence, dateValue)) {
                    return false;
                }
            }
        }
        return true;
    }
    
    @Nonnull
    @Override
    public String errorMessage(final String name, final TemporalAmount[] value) {
        return name + ((this.relationLower == null) ? "" : (" values should be " + this.relationLower.asText() + " " + String.valueOf(this.lower) + " and")) + ((this.relationUpper == null) ? "" : /* invokedynamic(!) */ProcyonInvokeDynamicHelper_20.invoke(this.relationUpper.asText(), String.valueOf(this.upper))) + ((this.relationSequence == null) ? "" : /* invokedynamic(!) */ProcyonInvokeDynamicHelper_21.invoke(this.relationSequence.asText())) + " values must all either be periods or durations but is " + Arrays.toString(value);
    }
    
    // This helper class was generated by Procyon to approximate the behavior of an
    // 'invokedynamic' instruction that it doesn't know how to interpret.
    private static final class ProcyonInvokeDynamicHelper_20
    {
        private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
        private static MethodHandle handle;
        private static volatile int fence;
        
        private static MethodHandle handle() {
            final MethodHandle handle = ProcyonInvokeDynamicHelper_20.handle;
            if (handle != null)
                return handle;
            return ProcyonInvokeDynamicHelper_20.ensureHandle();
        }
        
        private static MethodHandle ensureHandle() {
            ProcyonInvokeDynamicHelper_20.fence = 0;
            MethodHandle handle = ProcyonInvokeDynamicHelper_20.handle;
            if (handle == null) {
                MethodHandles.Lookup lookup = ProcyonInvokeDynamicHelper_20.LOOKUP;
                try {
                    handle = ((CallSite)StringConcatFactory.makeConcatWithConstants(lookup, "makeConcatWithConstants", MethodType.methodType(String.class, String.class, String.class), " values should be \u0001 \u0001 and")).dynamicInvoker();
                }
                catch (Throwable t) {
                    throw new UndeclaredThrowableException(t);
                }
                ProcyonInvokeDynamicHelper_20.fence = 1;
                ProcyonInvokeDynamicHelper_20.handle = handle;
                ProcyonInvokeDynamicHelper_20.fence = 0;
            }
            return handle;
        }
        
        private static String invoke(String p0, String p1) {
            try {
                return ProcyonInvokeDynamicHelper_20.handle().invokeExact(p0, p1);
            }
            catch (Throwable t) {
                throw new UndeclaredThrowableException(t);
            }
        }
    }
    
    // This helper class was generated by Procyon to approximate the behavior of an
    // 'invokedynamic' instruction that it doesn't know how to interpret.
    private static final class ProcyonInvokeDynamicHelper_21
    {
        private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
        private static MethodHandle handle;
        private static volatile int fence;
        
        private static MethodHandle handle() {
            final MethodHandle handle = ProcyonInvokeDynamicHelper_21.handle;
            if (handle != null)
                return handle;
            return ProcyonInvokeDynamicHelper_21.ensureHandle();
        }
        
        private static MethodHandle ensureHandle() {
            ProcyonInvokeDynamicHelper_21.fence = 0;
            MethodHandle handle = ProcyonInvokeDynamicHelper_21.handle;
            if (handle == null) {
                MethodHandles.Lookup lookup = ProcyonInvokeDynamicHelper_21.LOOKUP;
                try {
                    handle = ((CallSite)StringConcatFactory.makeConcatWithConstants(lookup, "makeConcatWithConstants", MethodType.methodType(String.class, String.class), " succeeding values should be \u0001 preceding values and")).dynamicInvoker();
                }
                catch (Throwable t) {
                    throw new UndeclaredThrowableException(t);
                }
                ProcyonInvokeDynamicHelper_21.fence = 1;
                ProcyonInvokeDynamicHelper_21.handle = handle;
                ProcyonInvokeDynamicHelper_21.fence = 0;
            }
            return handle;
        }
        
        private static String invoke(String p0) {
            try {
                return ProcyonInvokeDynamicHelper_21.handle().invokeExact(p0);
            }
            catch (Throwable t) {
                throw new UndeclaredThrowableException(t);
            }
        }
    }
}
