package org.innovateuk.ifs.application.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.innovateuk.ifs.commons.ZeroDowntime;
import org.innovateuk.ifs.file.domain.FileEntry;
import org.innovateuk.ifs.form.domain.FormInput;
import org.innovateuk.ifs.form.domain.Question;
import org.innovateuk.ifs.user.domain.ProcessRole;

import javax.persistence.*;
import java.time.ZonedDateTime;
import java.util.Set;

/**
 * Response class defines the model in which the response on a {@link Question} is stored.
 * For each question-application combination {@link Application} there can be a response.
 */
@Entity
public class FormInputResponse {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private ZonedDateTime updateDate;

    @Column(length = 5000)
    private String value;

    @ManyToOne(fetch = FetchType.EAGER, optional = false)
    @JoinColumn(name = "updatedById", referencedColumnName = "id")
    private ProcessRole updatedBy;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "formInputId", referencedColumnName = "id")
    private FormInput formInput;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "applicationId", referencedColumnName = "id")
    private Application application;

    @ZeroDowntime(reference = "IFS-7309", description = "TODO")
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "fileEntryId", referencedColumnName = "id")
    private FileEntry fileEntry;

//    @ElementCollection
//    @CollectionTable(name = "form_input_file_entry", joinColumns = {@JoinColumn(name="file_entry_id")})
//    @Column(name = "form_input_response_id")
//    private Set<Long> fileEntryIds = new LinkedHashSet<>();

    @ManyToMany(cascade = {CascadeType.PERSIST})
    @JoinTable(name = "form_input_file_entry",
            joinColumns = {@JoinColumn(name = "form_input_response_id")},
            inverseJoinColumns = {@JoinColumn(name = "fileEntryId", referencedColumnName = "id")})
    private Set<FileEntry> formInputFileEntry;

    public FormInputResponse() {
        // no-arg constructor
    }

    public FormInputResponse(ZonedDateTime updateDate, String value, ProcessRole updatedBy, FormInput formInput, Application application) {
        this.updateDate = updateDate;
        this.value = value;
        this.updatedBy = updatedBy;
        this.formInput = formInput;
        this.application = application;
    }

    public FormInputResponse(ZonedDateTime updateDate, FileEntry fileEntry, ProcessRole updatedBy, FormInput formInput, Application application) {
        this.updateDate = updateDate;
        this.fileEntry = fileEntry;
        this.updatedBy = updatedBy;
        this.formInput = formInput;
        this.application = application;
    }

    public Long getId() {
        return id;
    }

    void setId(Long id) {
        this.id = id;
    }

    public ZonedDateTime getUpdateDate() {
        return updateDate;
    }

    public String getValue() {
        return value;
    }

    @JsonIgnore
    public Integer getWordCount() {
        // this code removes the list items from the wysiwyg value.
        // If we don't then every list item will also count as one word.
        if (value != null) {
            String cleanInput = this.value.replaceAll("([0-9]+\\. |\\* |\\*\\*|_)", "");

            if (cleanInput.isEmpty()) {
                return 0;
            }

            return cleanInput.split("\\s+").length;
        } else {
            return 0;
        }
    }

    @JsonIgnore
    public Integer getWordCountLeft() {
        return formInput.getWordCount() - this.getWordCount();
    }

    public FormInput getFormInput() {
        return formInput;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public void setUpdateDate(ZonedDateTime updateDate) {
        this.updateDate = updateDate;
    }

    public void setFormInput(FormInput formInput) {
        this.formInput = formInput;
    }

    public ProcessRole getUpdatedBy() {
        return updatedBy;
    }

    public void setUpdatedBy(ProcessRole updatedBy) {
        this.updatedBy = updatedBy;
    }

    public FileEntry getFileEntry() {
        return fileEntry;
    }

    public void setFileEntry(FileEntry fileEntry) {
        this.fileEntry = fileEntry;
    }

    @JsonIgnore
    public Application getApplication() {
        return application;
    }

    public void setApplication(Application application) {
        this.application = application;
    }

    public Set<FileEntry> getFormInputFileEntry() {
        return formInputFileEntry;
    }

    public void setFormInputFileEntry(Set<FileEntry> formInputFileEntry) {
        this.formInputFileEntry = formInputFileEntry;
    }
}

@@ -416,18 +416,19 @@
 va.util.
-Se
+Lis
 t;%0A%0A/**%0A
@@ -1836,32 +1836,41 @@
 e = %22form_input_
+response_
 file_entry%22,%0A   
@@ -1884,33 +1884,32 @@
   joinColumns = 
-%7B
 @JoinColumn(name
@@ -1936,17 +1936,16 @@
 nse_id%22)
-%7D
 ,%0A      
@@ -1963,33 +1963,32 @@
 seJoinColumns = 
-%7B
 @JoinColumn(name
@@ -1987,38 +1987,40 @@
 umn(name = %22file
-E
+_e
 ntry
-I
+_i
 d%22, referencedCo
@@ -2035,17 +2035,16 @@
  = %22id%22)
-%7D
 )%0A    pr
@@ -2049,18 +2049,19 @@
 private 
-Se
+Lis
 t%3CFileEn
@@ -2066,32 +2066,40 @@
 Entry%3E formInput
+Response
 FileEntry;%0A%0A    
@@ -4590,18 +4590,19 @@
  public 
-Se
+Lis
 t%3CFileEn
@@ -4610,32 +4610,40 @@
 ry%3E getFormInput
+Response
 FileEntry() %7B%0A  
@@ -4656,32 +4656,40 @@
 return formInput
+Response
 FileEntry;%0A    %7D
@@ -4710,32 +4710,40 @@
 oid setFormInput
+Response
 FileEntry(Set%3CFi
@@ -4736,18 +4736,19 @@
 leEntry(
-Se
+Lis
 t%3CFileEn
@@ -4753,32 +4753,40 @@
 Entry%3E formInput
+Response
 FileEntry) %7B%0A   
@@ -4796,32 +4796,40 @@
   this.formInput
+Response
 FileEntry = form
@@ -4833,16 +4833,24 @@
 ormInput
+Response
 FileEntr

Update in FormInputResponse.formInputResponseFileEntry