package com.arms.api.issue.almapi.model.entity;


import com.arms.api.admin.indexdata.annotation.MonthBackup;
import com.arms.api.admin.indexdata.annotation.MonthMerge;
import com.arms.egovframework.javaservice.esframework.annotation.*;
import com.arms.egovframework.javaservice.esframework.model.entity.BaseEntity;
import com.fasterxml.jackson.annotation.*;
import lombok.*;

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.ReadOnlyProperty;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

@Builder(toBuilder = true)
@AllArgsConstructor
@Setter
@Getter
@Document(indexName = "#{@jiraissue}", createIndex = false)
@ElasticSearchTemplateConfig
@ElasticSearchIndex
@MonthBackup
@MonthMerge
@EqualsAndHashCode(exclude = {"recent","rawData"})
public class AlmIssueEntity implements BaseEntity {

    public AlmIssueEntity() {}

    @Id
    @ReadOnlyProperty
    private String id;

    @RecentId
    @JsonProperty("recent_id")
    @Field(type = FieldType.Keyword, name = "recent_id")
    private String recentId;

    @Recent
    @Field(type = FieldType.Boolean, name = "recent")
    private boolean recent;

    @Field(type = FieldType.Boolean, name = "isReq")
    private Boolean isReq;

    @Field(type = FieldType.Long, name = "cReqLink")
    private Long cReqLink ;

    @Field(type = FieldType.Long, name = "cReqStatusId")
    private Long cReqStatusId ;

    @Field(type = FieldType.Long, name = "pdServiceId")
    private Long pdServiceId;

    @Field(type = FieldType.Long, name = "pdServiceVersions")
    private List<Long> pdServiceVersions;

    @Field(type = FieldType.Long, name = "linkedIssuePdServiceIds")
    private List<Long> linkedIssuePdServiceIds;

    @Field(type = FieldType.Long, name = "linkedIssuePdServiceVersions")
    private List<Long> linkedIssuePdServiceVersions;

    @Field(type = FieldType.Keyword, name = "linkedIssues")
    private List<String> linkedIssues;

    @Field(type = FieldType.Keyword, name = "jira_server_id")
    private String jira_server_id;

    @Field(type = FieldType.Keyword, name = "key")
    private String key;

    @Field(type = FieldType.Keyword, name = "parentReqKey")
    private String parentReqKey;

    @Field(type = FieldType.Keyword, name = "upperKey")
    private String upperKey;

    @Field(type = FieldType.Auto, name = "issueID")
    private String issueID;

    @Field(type = FieldType.Text, name = "self")
    private String self;

    @Field(type = FieldType.Date, name = "@timestamp")
    @JsonProperty("@timestamp")
    @ElasticSearchUpdateDate
    private Date timestamp;

    @Field(type = FieldType.Auto, name = "etc")
    private Object etc;

    @Field(type = FieldType.Percolator, name = "queries")
    @JsonProperty("queries")
    private List<String> percolatorQueries;

    private Project project;

    private IssueType issuetype;

    private Creator creator;

    private Reporter reporter;

    private Assignee assignee;

    @Field(type = FieldType.Text)
    private List<String> labels;

    private Priority priority;

    private AlmIssueEntity.상태 status;

    @Field(type = FieldType.Keyword, name = "armsStateCategory")
    @JsonProperty("armsStateCategory")
    private String armsStateCategory;

    private Resolution resolution;

    @Field(type = FieldType.Date, name = "resolutiondate")
    private Date resolutiondate;

    @Field(type = FieldType.Date, name = "created")
    private Date created;

    @Field(type = FieldType.Date, name = "updated")
    private Date updated;

    @Field(type = FieldType.Date, name = "overallUpdatedDate")
    private Date overallUpdatedDate;

    private Deleted deleted;

    private List<Worklogs> worklogs;

    @Field(type = FieldType.Integer, name = "timespent")
    private Integer timespent;

    @Field(type = FieldType.Auto, name = "summary")
    private String summary;

    private CReqProperty cReqProperty;

    @JsonIgnore
    @Field(type = FieldType.Text, name = "rawData")
    private String rawData;

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class CReqProperty {
        @Field(type = FieldType.Long, name = "cReqPriorityLink")
        @JsonProperty("cReqPriorityLink")
        private Long cReqPriorityLink;

        @Field(type = FieldType.Keyword, name = "cReqPriorityName")
        @JsonProperty("cReqPriorityName")
        private String cReqPriorityName;

        @Field(type = FieldType.Long, name = "cReqDifficultyLink")
        @JsonProperty("cReqDifficultyLink")
        private Long cReqDifficultyLink;

        @Field(type = FieldType.Keyword, name = "cReqDifficultyName")
        @JsonProperty("cReqDifficultyName")
        private String cReqDifficultyName;

        @Field(type = FieldType.Long, name = "cReqStateLink")
        @JsonProperty("cReqStateLink")
        private Long cReqStateLink;

        @Field(type = FieldType.Keyword, name = "cReqStateName")
        @JsonProperty("cReqStateName")
        private String cReqStateName;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class Deleted {
        @Field(type = FieldType.Boolean, name = "deleted_isDeleted")
        @JsonProperty("deleted_isDeleted")
        private Boolean isDeleted;

        @Field(type = FieldType.Date, name = "deleted_date")
        @JsonProperty("deleted_date")
        private Date deleted_date;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class Project {
        @Field(type = FieldType.Text, name = "project_self")
        @JsonProperty("project_self")
        private String self;

        @Field(type = FieldType.Text, name = "project_id")
        @JsonProperty("project_id")
        private String id;

        @Field(type = FieldType.Text, name = "project_key")
        @JsonProperty("project_key")
        private String key;

        @Field(type = FieldType.Text, name = "project_name")
        @JsonProperty("project_name")
        private String name;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class IssueType {
        // 온프레미스, 클라우드 공통
        @Field(type = FieldType.Text, name = "issuetype_self")
        @JsonProperty("issuetype_self")
        private String self;

        @Field(type = FieldType.Text, name = "issuetype_id")
        @JsonProperty("issuetype_id")
        private String id;

        @Field(type = FieldType.Text, name = "issuetype_description")
        @JsonProperty("issuetype_description")
        private String description;

        @Field(type = FieldType.Text, name = "issuetype_name")
        @JsonProperty("issuetype_name")
        private String name;

        @Field(type = FieldType.Boolean, name = "issuetype_subtask")
        @JsonProperty("issuetype_subtask")
        private Boolean subtask;

        // 클라우드만 사용
        @Field(type = FieldType.Text, name = "issuetype_untranslatedName")
        @JsonProperty("issuetype_untranslatedName")
        private String untranslatedName;

        @Field(type = FieldType.Integer, name = "issuetype_hierarchyLevel")
        @JsonProperty("issuetype_hierarchyLevel")
        private Integer hierarchyLevel;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class Creator {

        @Field(type = FieldType.Text, name = "creator_accountId")
        @JsonProperty("creator_accountId")
        private String accountId;

        @Field(type = FieldType.Text, name = "creator_emailAddress")
        @JsonProperty("creator_emailAddress")
        private String emailAddress;

        @Field(type = FieldType.Text, name = "creator_displayName")
        @JsonProperty("creator_displayName")
        private String displayName;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class Reporter {

        @Field(type = FieldType.Text, name = "reporter_accountId")
        @JsonProperty("reporter_accountId")
        private String accountId;

        @Field(type = FieldType.Text, name = "reporter_emailAddress")
        @JsonProperty("reporter_emailAddress")
        private String emailAddress;

        @Field(type = FieldType.Text, name = "reporter_displayName")
        @JsonProperty("reporter_displayName")
        private String displayName;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class Assignee {

        @Field(type = FieldType.Text, name = "assignee_accountId")
        @JsonProperty("assignee_accountId")
        private String accountId;

        @Field(type = FieldType.Text, name = "assignee_emailAddress", fielddata = true)
        @JsonProperty("assignee_emailAddress")
        private String emailAddress;

        @Field(type = FieldType.Text, name = "assignee_displayName")
        @JsonProperty("assignee_displayName")
        private String displayName;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class Priority {

        // 온프레미스, 클라우드 공통
        @Field(type = FieldType.Text, name = "priority_self")
        @JsonProperty("priority_self")
        private String self;

        @Field(type = FieldType.Text, name = "priority_id")
        @JsonProperty("priority_id")
        private String id;

        @Field(type = FieldType.Text, name = "priority_name")
        @JsonProperty("priority_name")
        private String name;

        @Field(type = FieldType.Text, name = "priority_description")
        @JsonProperty("priority_description")
        private String description;

        // 클라우드
        @Field(type = FieldType.Boolean, name = "priority_isDefault")
        @JsonProperty("priority_isDefault")
        private boolean isDefault;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class 상태 {

        // 온프레미스, 클라우드 공통
        @Field(type = FieldType.Text, name = "status_self")
        @JsonProperty("status_self")
        private String self;

        @Field(type = FieldType.Text, name = "status_id")
        @JsonProperty("status_id")
        private String id;

        @Field(type = FieldType.Text, name = "status_name", fielddata = true)
        @JsonProperty("status_name")
        private String name;

        @Field(type = FieldType.Text, name = "status_description")
        @JsonProperty("status_description")
        private String description;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class Resolution {


        // 온프레미스, 클라우드 공통
        @Field(type = FieldType.Text, name = "resolution_self")
        @JsonProperty("resolution_self")
        private String self;

        @Field(type = FieldType.Text, name = "resolution_id")
        @JsonProperty("resolution_id")
        private String id;

        @Field(type = FieldType.Text, name = "resolution_name")
        @JsonProperty("resolution_name")
        private String name;

        @Field(type = FieldType.Text, name = "resolution_description")
        @JsonProperty("resolution_description")
        private String description;

        // 클라우드
        @Field(type = FieldType.Boolean, name = "resolution_isDefault")
        @JsonProperty("resolution_isDefault")
        private boolean isDefault;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class Worklogs {

        @Field(type = FieldType.Text, name = "worklogs_self")
        @JsonProperty("worklogs_self")
        private String self;

        @Field(type = FieldType.Nested)
        private Author author;

        @Field(type = FieldType.Nested)
        private UpdateAuthor updateAuthor;

        @Field(type = FieldType.Text, name = "worklogs_created")
        @JsonProperty("worklogs_created")
        private String created;

        @Field(type = FieldType.Text, name = "worklogs_updated")
        @JsonProperty("worklogs_updated")
        private String updated;

        @Field(type = FieldType.Text, name = "worklogs_started")
        @JsonProperty("worklogs_started")
        private String started;

        @Field(type = FieldType.Text, name = "worklogs_timeSpent")
        @JsonProperty("worklogs_timeSpent")
        private String timeSpent;

        @Field(type = FieldType.Integer, name = "worklogs_timeSpentSeconds")
        @JsonProperty("worklogs_timeSpentSeconds")
        private Integer timeSpentSeconds;

        @Field(type = FieldType.Text, name = "worklogs_id")
        @JsonProperty("worklogs_id")
        private String id;

        @Field(type = FieldType.Text, name = "worklogs_issueId")
        @JsonProperty("worklogs_issueId")
        private String issueId;
    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class Author {

        @Field(type = FieldType.Text, name = "worklogs_author_accountId")
        @JsonProperty("worklogs_author_accountId")
        private String accountId;

        @Field(type = FieldType.Text, name = "worklogs_author_emailAddress")
        @JsonProperty("worklogs_author_emailAddress")
        private String emailAddress;

    }

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @EqualsAndHashCode
    public static class UpdateAuthor {

        @Field(type = FieldType.Text, name = "worklogs_updateAuthor_accountId")
        @JsonProperty("worklogs_updateAuthor_accountId")
        private String accountId;

        @Field(type = FieldType.Text, name = "worklogs_updateAuthor_emailAddress")
        @JsonProperty("worklogs_updateAuthor_emailAddress")
        private String emailAddress;

    }

    public void generateId() {
        this.recentId = this.jira_server_id + "_" +this.project.key + "_" + this.key;
    }

    public boolean izEmpty(){
        return recentId ==null|| recentId.isEmpty();
    }

    public boolean izNotEmpty(){
        return !this.izEmpty();
    }

    public String recentId(){
        return this.recentId;
    }

    public String recentIdByNewKey(String newKey){
        return this.jira_server_id + "_" +this.project.key + "_" + newKey;
    }

    private void modifyKey(String projectKey, String newKey){
        this.key = newKey;
        this.project.key  = projectKey;
        this.recentId = recentIdByNewKey(newKey);
    }

    public void modifyProjectKeyAndKey(String projectKey, String newKey){
        modifyKey(projectKey, newKey);
    }

    public boolean isNeedOverallUpdatedDate(AlmIssueEntity targetAlmIssueEntity) {
        if(targetAlmIssueEntity.getUpdated()==null){
            return false;
        }
        return this.overallUpdatedDate.after(targetAlmIssueEntity.getUpdated());
    }

    public boolean izReqTrue(){
        return isReq!=null&&isReq;
    }

    public boolean izReqFalse(){
        return !izReqTrue();
    }

    public String stringValueOfResolutionDate() {

        if(resolutiondate!=null){
            ZonedDateTime zdt = resolutiondate.toInstant().atZone(ZoneId.systemDefault());

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

            return zdt.format(formatter);
        }

        return null;
    }


    public String stringValueOfCreatedDate() {

        if(created!=null){
            ZonedDateTime zdt = created.toInstant().atZone(ZoneId.systemDefault());

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

            return zdt.format(formatter);
        }

        return null;
    }

    public String stringValueOfUpdatedDate() {

        if(updated!=null){
            ZonedDateTime zdt = updated.toInstant().atZone(ZoneId.systemDefault());

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

            return zdt.format(formatter);
        }

        return null;
    }

    @RollingIndexName
    public String localDate() {
        Date now = new Date();
        // 타임스탬프를 UTC+9로 변환
        LocalDateTime localDateTime = LocalDateTime.ofInstant(now.toInstant(), ZoneId.of("UTC+9"));
        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("UTC+9"));
        now = java.util.Date.from(zonedDateTime.toInstant());
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        return formatter.format(now);
    }


}
