package com.ankurm.idgen.extra;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Member;
import java.util.EnumSet;
import java.util.UUID;
import org.hibernate.annotations.IdGeneratorType;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.BeforeExecutionGenerator;
import org.hibernate.generator.EventType;
import org.hibernate.generator.GeneratorCreationContext;
import org.hibernate.id.uuid.UuidVersion7Strategy;

/*
 * A custom id annotation built on @IdGeneratorType instead of @UuidGenerator: your own name (@Uuid7), and it also
 * works on a String id. The types are package-private so this one file can be saved under any name; make them
 * public (one per file) when you move them into a real project.
 */
@IdGeneratorType(Uuid7Generator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@interface Uuid7 {
}

class Uuid7Generator implements BeforeExecutionGenerator {

    private final boolean asString;

    /** Hibernate calls this constructor with the annotation instance, the annotated member and a creation context. */
    Uuid7Generator(Uuid7 annotation, Member member, GeneratorCreationContext context) {
        Class<?> type = member instanceof java.lang.reflect.Field f ? f.getType() : ((java.lang.reflect.Method) member).getReturnType();
        this.asString = type == String.class;
    }

    @Override
    public EnumSet<EventType> getEventTypes() {
        return EnumSet.of(EventType.INSERT);
    }

    @Override
    public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
        UUID id = UuidVersion7Strategy.INSTANCE.generateUuid(session);
        return asString ? id.toString() : id;
    }
}
