package de.accso.flexinale.ticketing.domain.model;

import de.accso.flexinale.common.shared_kernel.DoNotCheckInArchitectureTests;
import de.accso.flexinale.common.shared_kernel.EqualsByContent;
import de.accso.flexinale.common.shared_kernel.Identifiable;
import de.accso.flexinale.common.shared_kernel.Versionable;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

public class Ticket implements Identifiable, Versionable, EqualsByContent {

    public enum VerkaufsKanal {
        ONLINE,
        ZENTRAL,
        KINOKASSE
    }

    public final Id id;
    public final Version version;

    public final Id filmId;
    public final Id vorfuehrungId;
    public final Id besucherId;

    @DoNotCheckInArchitectureTests
    public VerkaufsKanal verkaufsKanal;

    //TODO why would we need to set the ID from outside at all? Why not leave it to the class internally?
    public Ticket(final Id id,
                  final Id filmId, final Id vorfuehrungId, final Id besucherId,
                  final VerkaufsKanal verkaufsKanal) {
        this(id, Versionable.unknownVersion(), filmId, vorfuehrungId, besucherId,  verkaufsKanal);
    }

    public Ticket(final Id id, final Version version,
                  final Id filmId, final Id vorfuehrungId, final Id besucherId,
                  final VerkaufsKanal verkaufsKanal) {
        this.id = id;
        this.version = version;
        this.filmId = filmId;
        this.vorfuehrungId = vorfuehrungId;
        this.besucherId = besucherId;
        this.verkaufsKanal = verkaufsKanal;
    }

    @Override
    public Id id() {
        return id;
    }

    @Override
    public Version version() {
        return version;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }

    @Override
    public boolean equals(final Object o) {
        if (!equalsByContent(o)) return false;

        if (this == o) {return true;}
        if (o == null || getClass() != o.getClass()) {return false;}
        Ticket that = (Ticket) o;
        return new EqualsBuilder().append(version, that.version).isEquals();
    }

    @Override
    public boolean equalsByContent(final Object o) {
        if (this == o) {return true;}

        if (o == null || getClass() != o.getClass()) {return false;}

        Ticket that = (Ticket) o;

        return new EqualsBuilder()
                .append(id, that.id)
                .append(filmId, that.filmId)
                .append(vorfuehrungId, that.vorfuehrungId)
                .append(besucherId, that.besucherId)
                .append(verkaufsKanal, that.verkaufsKanal)
                .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17, 37)
                .append(id).append(version)
                .append(filmId).append(vorfuehrungId).append(besucherId)
                .append(verkaufsKanal)
                .toHashCode();
    }
}
