package com.aegis.resource.procurement.domain;

import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import com.aegis.common.core.domain.BaseEntity;
import com.aegis.common.exception.ServiceException;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * 采购申请实体类 resource_procurement
 * 
 * @author aegis
 */
@Getter
@Setter
@ToString(callSuper = true)
public class Procurement extends BaseEntity {
    
    private static final long serialVersionUID = 1L;

    /** 采购ID */
    private Long id;

    /** 采购编号 */
    private String procurementNo;

    /** 采购标题 */
    private String title;

    /** 紧急程度：low-低，normal-普通，high-高，urgent-紧急 */
    private String urgency;

    /** 状态：draft-草稿，submitted-已提交，approved-已审核，rejected-已驳回，in_progress-进行中，received-已入库 */
    private String status;

    /** 中标供应商ID */
    private Long awardedSupplierId;

    /** 中标供应商名称（关联查询，不持久化） */
    private transient String awardedSupplierName;

    /** 中标时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date awardedAt;

    /** 审核人ID */
    private Long approverId;

    /** 审核人姓名 */
    private String approverName;

    /** 审核时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date approvedAt;

    /** 审核意见 */
    private String approvalComment;

    /** 删除标志（0代表存在 2代表删除） */
    private String delFlag;

    /**
     * 初始化默认值
     * 
     * @param operator 操作人
     */
    public void initializeDefaults(String operator) {
        if (StringUtils.isBlank(this.status)) {
            this.status = ProcurementStatus.DRAFT.getCode();
        }
        if (StringUtils.isBlank(this.urgency)) {
            this.urgency = ProcurementUrgency.NORMAL.getCode();
        }
    }

    /**
     * 提交采购申请（draft → submitted）
     * 
     * @param operator 操作人
     */
    public void submit(String operator) {
        this.ensureNotDeleted();
        ProcurementStatus current = this.getStatusEnum();
        if (!ProcurementStatus.DRAFT.equals(current)) {
            throw new ServiceException("只有草稿状态的采购申请才能提交");
        }
        this.setStatusEnum(ProcurementStatus.SUBMITTED);
        this.touch(operator);
    }

    /**
     * 审核通过（submitted → approved）
     * 
     * @param approverId 审核人ID
     * @param approverName 审核人姓名
     * @param comment 审核意见
     * @param operator 操作人
     */
    public void approve(Long approverId, String approverName, String comment, String operator) {
        this.ensureNotDeleted();
        ProcurementStatus current = this.getStatusEnum();
        if (!ProcurementStatus.SUBMITTED.equals(current)) {
            throw new ServiceException("只有已提交状态的采购申请才能审核");
        }
        this.setStatusEnum(ProcurementStatus.APPROVED);
        this.approverId = approverId;
        this.approverName = approverName;
        this.approvedAt = new Date();
        this.approvalComment = comment;
        this.touch(operator);
    }

    /**
     * 审核驳回（submitted → rejected）
     * 
     * @param approverId 审核人ID
     * @param approverName 审核人姓名
     * @param comment 审核意见
     * @param operator 操作人
     */
    public void reject(Long approverId, String approverName, String comment, String operator) {
        this.ensureNotDeleted();
        ProcurementStatus current = this.getStatusEnum();
        if (!ProcurementStatus.SUBMITTED.equals(current)) {
            throw new ServiceException("只有已提交状态的采购申请才能审核");
        }
        this.setStatusEnum(ProcurementStatus.REJECTED);
        this.approverId = approverId;
        this.approverName = approverName;
        this.approvedAt = new Date();
        this.approvalComment = comment;
        this.touch(operator);
    }

    /**
     * 确认中标（approved → in_progress）
     * 
     * @param supplierId 中标供应商ID
     * @param operator 操作人
     */
    public void award(Long supplierId, String operator) {
        this.ensureNotDeleted();
        ProcurementStatus current = this.getStatusEnum();
        if (!ProcurementStatus.APPROVED.equals(current)) {
            throw new ServiceException("只有已审核通过状态的采购申请才能确认中标");
        }
        this.setStatusEnum(ProcurementStatus.IN_PROGRESS);
        this.awardedSupplierId = supplierId;
        this.awardedAt = new Date();
        this.touch(operator);
    }

    /**
     * 采购入库（in_progress → received）
     * 
     * @param operator 操作人
     */
    public void receive(String operator) {
        this.ensureNotDeleted();
        ProcurementStatus current = this.getStatusEnum();
        if (!ProcurementStatus.IN_PROGRESS.equals(current)) {
            throw new ServiceException("只有进行中状态的采购申请才能入库");
        }
        this.setStatusEnum(ProcurementStatus.RECEIVED);
        this.touch(operator);
    }

    /**
     * 重新提交（rejected → submitted）
     * 驳回后修改完成，直接提交审核
     * 
     * @param operator 操作人
     */
    public void resubmit(String operator) {
        this.ensureNotDeleted();
        ProcurementStatus current = this.getStatusEnum();
        if (!ProcurementStatus.REJECTED.equals(current)) {
            throw new ServiceException("只有已驳回状态的采购申请才能重新提交");
        }
        // 直接提交审核，不经过草稿状态
        this.setStatusEnum(ProcurementStatus.SUBMITTED);
        this.touch(operator);
    }

    /**
     * 标记为已删除
     * 
     * @param operator 操作人
     */
    public void markDeleted(String operator) {
        if (this.isDeleted()) {
            return;
        }
        ProcurementStatus current = this.getStatusEnum();
        if (!ProcurementStatus.DRAFT.equals(current)) {
            throw new ServiceException("只有草稿状态的采购申请才能删除");
        }
        this.delFlag = DEL_FLAG_DELETED;
        this.touch(operator);
    }

    /**
     * 恢复（取消删除）
     * 
     * @param operator 操作人
     */
    public void restore(String operator) {
        if (this.isDeleted()) {
            this.delFlag = DEL_FLAG_NORMAL;
            this.touch(operator);
        }
    }

    /**
     * 修改采购标题
     * 
     * @param newTitle 新标题
     * @param operator 操作人
     */
    public void changeTitle(String newTitle, String operator) {
        this.ensureNotDeleted();
        this.ensureEditable();
        if (StringUtils.isBlank(newTitle)) {
            throw new ServiceException("采购标题不能为空");
        }
        if (newTitle.length() > 200) {
            throw new ServiceException("采购标题长度不能超过200个字符");
        }
        this.title = newTitle;
        this.touch(operator);
    }

    /**
     * 修改紧急程度
     * 
     * @param urgency 紧急程度
     * @param operator 操作人
     */
    public void changeUrgency(String urgency, String operator) {
        this.ensureNotDeleted();
        this.ensureEditable();
        if (StringUtils.isNotBlank(urgency) && ProcurementUrgency.fromCode(urgency) == null) {
            throw new ServiceException("无效的紧急程度: " + urgency);
        }
        this.urgency = urgency;
        this.touch(operator);
    }

    /**
     * 修改备注
     * 
     * @param remark 备注
     * @param operator 操作人
     */
    public void changeRemark(String remark, String operator) {
        this.ensureNotDeleted();
        if (StringUtils.isNotBlank(remark) && remark.length() > 500) {
            throw new ServiceException("备注长度不能超过500个字符");
        }
        this.setRemark(remark);
        this.touch(operator);
    }

    /**
     * 确保采购申请未被删除
     */
    public void ensureNotDeleted() {
        if (this.isDeleted()) {
            throw new ServiceException("已删除的采购申请不允许该操作");
        }
    }

    /**
     * 确保采购申请可编辑（草稿和驳回状态可编辑）
     */
    public void ensureEditable() {
        ProcurementStatus current = this.getStatusEnum();
        if (!ProcurementStatus.DRAFT.equals(current) && !ProcurementStatus.REJECTED.equals(current)) {
            throw new ServiceException("只有草稿或已驳回状态的采购申请才能编辑");
        }
    }

    /**
     * 检查是否已删除
     * 
     * @return 是否已删除
     */
    private boolean isDeleted() {
        return DEL_FLAG_DELETED.equals(delFlag);
    }

    /**
     * 获取状态枚举
     * 
     * @return 状态枚举
     */
    public ProcurementStatus getStatusEnum() {
        return ProcurementStatus.fromCode(status);
    }

    /**
     * 设置状态枚举
     * 
     * @param status 状态枚举
     */
    private void setStatusEnum(ProcurementStatus status) {
        this.status = status.getCode();
    }

    /**
     * 更新操作信息
     * 
     * @param operator 操作人
     */
    private void touch(String operator) {
        this.setUpdateBy(operator);
        this.setUpdateTime(new Date());
    }

    private static final String DEL_FLAG_NORMAL = "0";
    private static final String DEL_FLAG_DELETED = "2";

    /**
     * 采购状态枚举
     */
    public enum ProcurementStatus {
        DRAFT("draft", "草稿"),
        SUBMITTED("submitted", "已提交"),
        APPROVED("approved", "已审核"),
        REJECTED("rejected", "已驳回"),
        IN_PROGRESS("in_progress", "进行中"),
        RECEIVED("received", "已入库");

        private final String code;
        private final String label;

        ProcurementStatus(String code, String label) {
            this.code = code;
            this.label = label;
        }

        public String getCode() {
            return code;
        }

        public String getLabel() {
            return label;
        }

        public static ProcurementStatus fromCode(String code) {
            if (StringUtils.isBlank(code)) {
                return DRAFT;
            }
            for (ProcurementStatus value : values()) {
                if (value.code.equals(code)) {
                    return value;
                }
            }
            return DRAFT;
        }
    }

    /**
     * 紧急程度枚举
     */
    public enum ProcurementUrgency {
        LOW("low", "低"),
        NORMAL("normal", "普通"),
        HIGH("high", "高"),
        URGENT("urgent", "紧急");

        private final String code;
        private final String label;

        ProcurementUrgency(String code, String label) {
            this.code = code;
            this.label = label;
        }

        public String getCode() {
            return code;
        }

        public String getLabel() {
            return label;
        }

        public static ProcurementUrgency fromCode(String code) {
            if (StringUtils.isBlank(code)) {
                return NORMAL;
            }
            for (ProcurementUrgency value : values()) {
                if (value.code.equals(code)) {
                    return value;
                }
            }
            return NORMAL;
        }
    }
}