package ru.ulstu.grant.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.NotEmpty;
import ru.ulstu.deadline.model.Deadline;
import ru.ulstu.file.model.FileDataDto;
import ru.ulstu.name.NameContainer;
import ru.ulstu.paper.model.PaperDto;
import ru.ulstu.project.model.ProjectDto;
import ru.ulstu.user.model.UserDto;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static ru.ulstu.core.util.StreamApiUtils.convert;

public class GrantDto extends NameContainer {
    private final static int MAX_AUTHORS_LENGTH = 60;

    private Integer id;
    @NotEmpty
    private String title;
    private Grant.GrantStatus status;
    private List<Deadline> deadlines = new ArrayList<>();
    private String comment;
    private List<FileDataDto> files = new ArrayList<>();
    private ProjectDto project;
    private Set<Integer> authorIds;
    private Set<UserDto> authors;
    private Integer leaderId;
    private boolean wasLeader;
    private boolean hasAge;
    private boolean hasDegree;
    private boolean hasBAKPapers;
    private boolean hasScopusPapers;
    private List<Integer> paperIds = new ArrayList<>();
    private List<PaperDto> papers = new ArrayList<>();
    private List<Integer> removedDeadlineIds = new ArrayList<>();

    public GrantDto() {
        deadlines.add(new Deadline());
    }

    @JsonCreator
    public GrantDto(@JsonProperty("id") Integer id,
                    @JsonProperty("title") String title,
                    @JsonProperty("status") Grant.GrantStatus status,
                    @JsonProperty("deadlines") List<Deadline> deadlines,
                    @JsonProperty("comment") String comment,
                    @JsonProperty("files") List<FileDataDto> files,
                    @JsonProperty("project") ProjectDto project,
                    @JsonProperty("authorIds") Set<Integer> authorIds,
                    @JsonProperty("authors") Set<UserDto> authors,
                    @JsonProperty("leaderId") Integer leaderId,
                    @JsonProperty("wasLeader") boolean wasLeader,
                    @JsonProperty("hasAge") boolean hasAge,
                    @JsonProperty("hasDegree") boolean hasDegree,
                    @JsonProperty("paperIds") List<Integer> paperIds,
                    @JsonProperty("papers") List<PaperDto> papers) {
        this.id = id;
        this.title = title;
        this.status = status;
        this.deadlines = deadlines;
        this.comment = comment;
        this.files = files;
        this.project = project;
        this.authorIds = authorIds;
        this.authors = authors;
        this.leaderId = leaderId;
        this.wasLeader = wasLeader;
        this.hasAge = hasAge;
        this.hasDegree = hasDegree;
        this.paperIds = paperIds;
        this.papers = papers;
    }

    public GrantDto(Grant grant) {
        this.id = grant.getId();
        this.title = grant.getTitle();
        this.status = grant.getStatus();
        this.deadlines = grant.getDeadlines();
        this.comment = grant.getComment();
        this.files = convert(grant.getFiles(), FileDataDto::new);
        this.project = grant.getProject() == null ? null : new ProjectDto(grant.getProject());
        this.authorIds = convert(grant.getAuthors(), user -> user.getId());
        this.authors = convert(grant.getAuthors(), UserDto::new);
        this.leaderId = grant.getLeader().getId();
        this.wasLeader = false;
        this.hasAge = false;
        this.hasDegree = false;
        this.paperIds = convert(grant.getPapers(), paper -> paper.getId());
        this.papers = convert(grant.getPapers(), PaperDto::new);
    }

    public GrantDto(String grantTitle, Date deadLineDate) {
        this.title = grantTitle;
        deadlines.add(new Deadline(deadLineDate, "Окончание приёма заявок"));
        status = Grant.GrantStatus.LOADED_FROM_KIAS;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Grant.GrantStatus getStatus() {
        return status;
    }

    public void setStatus(Grant.GrantStatus status) {
        this.status = status;
    }

    public List<Deadline> getDeadlines() {
        return deadlines;
    }

    public void setDeadlines(List<Deadline> deadlines) {
        this.deadlines = deadlines;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public List<FileDataDto> getFiles() {
        return files;
    }

    public void setFiles(List<FileDataDto> files) {
        this.files = files;
    }

    public ProjectDto getProject() {
        return project;
    }

    public void setProject(ProjectDto project) {
        this.project = project;
    }

    public Set<Integer> getAuthorIds() {
        return authorIds;
    }

    public void setAuthorIds(Set<Integer> authorIds) {
        this.authorIds = authorIds;
    }

    public Set<UserDto> getAuthors() {
        return authors;
    }

    public void setAuthors(Set<UserDto> authors) {
        this.authors = authors;
    }

    public String getAuthorsString() {
        return StringUtils.abbreviate(authors
                .stream()
                .map(author -> author.getLastName())
                .collect(Collectors.joining(", ")), MAX_AUTHORS_LENGTH);
    }

    public Integer getLeaderId() {
        return leaderId;
    }

    public void setLeaderId(Integer leaderId) {
        this.leaderId = leaderId;
    }

    public boolean isWasLeader() {
        return wasLeader;
    }

    public void setWasLeader(boolean wasLeader) {
        this.wasLeader = wasLeader;
    }

    public boolean isHasAge() {
        return hasAge;
    }

    public void setHasAge(boolean hasAge) {
        this.hasAge = hasAge;
    }

    public boolean isHasDegree() {
        return hasDegree;
    }

    public void setHasDegree(boolean hasDegree) {
        this.hasDegree = hasDegree;
    }

    public List<Integer> getPaperIds() {
        return paperIds;
    }

    public void setPaperIds(List<Integer> paperIds) {
        this.paperIds = paperIds;
    }

    public List<PaperDto> getPapers() {
        return papers;
    }

    public void setPapers(List<PaperDto> papers) {
        this.papers = papers;
    }

    public List<Integer> getRemovedDeadlineIds() {
        return removedDeadlineIds;
    }

    public void setRemovedDeadlineIds(List<Integer> removedDeadlineIds) {
        this.removedDeadlineIds = removedDeadlineIds;
    }

    public boolean isHasBAKPapers() {
        return hasBAKPapers;
    }

    public void setHasBAKPapers(boolean hasBAKPapers) {
        this.hasBAKPapers = hasBAKPapers;
    }

    public boolean isHasScopusPapers() {
        return hasScopusPapers;
    }

    public void setHasScopusPapers(boolean hasScopusPapers) {
        this.hasScopusPapers = hasScopusPapers;
    }
}