// Licensed under Apache-2.0
package org.hostsharing.hsadminng.service.accessfilter;

import static org.hostsharing.hsadminng.service.accessfilter.Role.*;

import org.hostsharing.hsadminng.service.IdToDtoResolver;
import org.hostsharing.hsadminng.service.dto.FluentBuilder;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;

import java.math.BigDecimal;
import java.time.LocalDate;

public class JSonAccessFilterTestFixture {

    static GivenDto createSampleDto() {
        final GivenDto dto = new GivenDto();
        dto.customerId = 888L;
        dto.restrictedField = RandomStringUtils.randomAlphabetic(10);
        dto.openStringField = RandomStringUtils.randomAlphabetic(10);
        dto.openIntegerField = RandomUtils.nextInt();
        dto.openPrimitiveIntField = RandomUtils.nextInt();
        dto.openLongField = RandomUtils.nextLong();
        dto.openPrimitiveLongField = RandomUtils.nextLong();
        dto.openBooleanField = true;
        dto.openPrimitiveBooleanField = false;
        dto.openBigDecimalField = new BigDecimal("987654321234567890987654321234567890.09");
        dto.openLocalDateField = LocalDate.parse("2019-04-25");
        dto.openLocalDateFieldAsString = "2019-04-25";
        dto.openEnumField = TestEnum.GREEN;
        dto.openEnumFieldAsString = "GREEN";
        return dto;
    }

    @EntityTypeId("test.GivenCustomer")
    static class GivenCustomerDto implements FluentBuilder<GivenCustomerDto> {

        @SelfId(resolver = GivenService.class)
        @AccessFor(read = ANYBODY)
        Long id;

        @AccessFor(update = IGNORED, read = ANYBODY)
        String displayLabel;

    }

    static abstract class GivenCustomerService implements IdToDtoResolver<GivenCustomerDto> {
    }

    @EntityTypeId("test.Given")
    static class GivenDto implements AccessMappings, FluentBuilder<GivenDto> {

        @SelfId(resolver = GivenService.class)
        @AccessFor(read = ANYBODY)
        Long id;

        @ParentId(resolver = GivenCustomerService.class)
        @AccessFor(init = ANY_CUSTOMER_USER, update = ANY_CUSTOMER_USER, read = ANY_CUSTOMER_USER)
        Long customerId;

        @AccessFor(
                init = { CUSTOMER_TECHNICAL_CONTACT, CUSTOMER_FINANCIAL_CONTACT },
                update = { CUSTOMER_TECHNICAL_CONTACT, CUSTOMER_FINANCIAL_CONTACT },
                read = { CUSTOMER_TECHNICAL_CONTACT, CUSTOMER_FINANCIAL_CONTACT })
        String restrictedField;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        String openStringField;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        Integer openIntegerField;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        int openPrimitiveIntField;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        Long openLongField;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        long openPrimitiveLongField;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        Boolean openBooleanField;

        @AccessFor(read = ANYBODY)
        boolean openPrimitiveBooleanField;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        LocalDate openLocalDateField;
        transient String openLocalDateFieldAsString;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        LocalDate openLocalDateField2;
        transient String openLocalDateField2AsString;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        TestEnum openEnumField;
        transient String openEnumFieldAsString;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        BigDecimal openBigDecimalField;

        @AccessFor(init = SUPPORTER, update = SUPPORTER, read = SUPPORTER)
        BigDecimal restrictedBigDecimalField;

        @AccessFor(init = ANYBODY, update = ANYBODY, read = ANYBODY)
        int[] openArrayField;

        @AccessFor(init = IGNORED, update = IGNORED, read = ANYBODY)
        String displayLabel;

        @Override
        public Long getId() {
            return id;
        }
    }

    static abstract class GivenService implements IdToDtoResolver<GivenDto> {
    }

    enum TestEnum {
        BLUE,
        GREEN
    }

    static abstract class GivenChildService implements IdToDtoResolver<GivenChildDto> {
    }

    public static class GivenChildDto implements AccessMappings, FluentBuilder<GivenChildDto> {

        @SelfId(resolver = GivenChildService.class)
        @AccessFor(read = Role.ANY_CUSTOMER_USER)
        Long id;

        @AccessFor(
                init = Role.CUSTOMER_CONTRACTUAL_CONTACT,
                update = Role.CUSTOMER_CONTRACTUAL_CONTACT,
                read = ANY_CUSTOMER_USER)
        @ParentId(resolver = GivenService.class)
        Long parentId;

        @AccessFor(
                init = { CUSTOMER_TECHNICAL_CONTACT, CUSTOMER_FINANCIAL_CONTACT },
                update = {
                        CUSTOMER_TECHNICAL_CONTACT,
                        CUSTOMER_FINANCIAL_CONTACT })
        String restrictedField;

        @Override
        public Long getId() {
            return id;
        }
    }

    public static class GivenDtoWithMultipleSelfId implements AccessMappings {

        @SelfId(resolver = GivenChildService.class)
        @AccessFor(read = Role.ANY_CUSTOMER_USER)
        Long id;

        @SelfId(resolver = GivenChildService.class)
        @AccessFor(read = Role.ANY_CUSTOMER_USER)
        Long id2;

        @Override
        public Long getId() {
            return id;
        }
    }

    public static class GivenDtoWithUnknownFieldType implements AccessMappings {

        @SelfId(resolver = GivenChildService.class)
        @AccessFor(read = Role.ANYBODY)
        Long id;

        @AccessFor(init = Role.ANYBODY, read = Role.ANYBODY)
        Arbitrary unknown;

        @Override
        public Long getId() {
            return id;
        }
    }

    public static class Arbitrary {
    }

    @EntityTypeId("givenParent")
    public static class GivenParent implements AccessMappings, FluentBuilder<GivenParent> {

        @SelfId(resolver = GivenParentService.class)
        @AccessFor(read = Role.ANY_CUSTOMER_USER)
        Long id;

        @Override
        public Long getId() {
            return id;
        }

        public GivenParent id(final long id) {
            this.id = id;
            return this;
        }
    }

    public static class GivenChild implements AccessMappings, FluentBuilder<GivenChild> {

        @SelfId(resolver = GivenChildService.class)
        @AccessFor(read = Role.ANY_CUSTOMER_USER)
        Long id;

        @AccessFor(
                init = Role.CUSTOMER_CONTRACTUAL_CONTACT,
                update = Role.CUSTOMER_CONTRACTUAL_CONTACT,
                read = ANY_CUSTOMER_USER)
        @ParentId(resolver = GivenParentService.class)
        GivenParent parent;

        @AccessFor(
                init = { CUSTOMER_TECHNICAL_CONTACT, CUSTOMER_FINANCIAL_CONTACT },
                update = {
                        CUSTOMER_TECHNICAL_CONTACT,
                        CUSTOMER_FINANCIAL_CONTACT })
        String restrictedField;

        @Override
        public Long getId() {
            return id;
        }
    }

    static abstract class GivenParentService implements IdToDtoResolver<GivenParent> {
    }

}
