package com.gci.boot.common.util;

import com.gci.boot.exception.GciBootException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * 参数校验工具
 */
@Slf4j
public final class ParamsCheckUtil {

    public static void assertTrue(boolean expr, String msg) {
        if (!expr) {
            throw new GciBootException(msg);
        }
    }

    public static void assertNotNull(Object val, String msg) {
        if (val == null) {
            throw new GciBootException(msg);
        }
    }

    public static void assertNotBlank(Object val, String msg) {
        if (val == null || val.toString().trim().length() == 0) {
            throw new GciBootException(msg);
        }
    }

    public static void assertDateBefore(boolean condition, Date date, Date right, String msg) {
        if (!condition) {
            return;
        }
        if (date != null && right != null && date.after(right)) {
            throw new GciBootException(msg);
        }
    }

    public static void assertDateAfter(boolean condition, Date date, Date left, String msg) {
        if (!condition) {
            return;
        }
        if (date != null && left != null && date.before(left)) {
            throw new GciBootException(msg);
        }
    }

    public static void assertDateBefore(Date date, Date right, String msg) {
        assertDateBefore(true, date, right, msg);
    }

    public static void assertDateAfter(Date date, Date left, String msg) {
        assertDateAfter(true, date, left, msg);
    }

    public static ParamsAssert paramsAssert() {
        return new ParamsAssert();
    }

    public static ParamsCheck paramsCheck() {
        return new ParamsCheck();
    }


    @AllArgsConstructor
    @Data
    private static class ValueCheck {
        private Object val;
        private String msg;
    }

    @AllArgsConstructor
    @Data
    private static class DateCheck {
        private Date date;
        private Date leftDate;
        private Date rightDate;
        private String dateName;
        private String leftDateName;
        private String rightDateName;
        private String message;

    }

    public static class ParamsAssert {

        private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

        public ParamsAssert() {
        }


        public ParamsAssert datePattern(String pattern) {
            this.dateFormat = new SimpleDateFormat(pattern);
            return this;
        }

        public ParamsAssert isTrue(boolean val, String msg) {
            assertTrue(val, msg);
            return this;
        }
        public ParamsAssert notNull(boolean condition, Object val, String msg) {
            if (!condition) {
                return this;
            }
            assertNotNull(val, msg);
            return this;
        }

        public ParamsAssert notBlank(boolean condition, Object val, String msg) {
            if (!condition) {
                return this;
            }
            assertNotBlank(val, msg);
            return this;
        }


        public ParamsAssert dateBefore(boolean condition, Date date, Date rightDate, String dateName, String rightDateName) {
            assertDateBefore(condition, date, rightDate, String.format("%s【%s】不能晚于%s【%s】", dateName, dateFormat.format(date), rightDateName, dateFormat.format(rightDate)));
            return this;
        }

        public ParamsAssert dateAfter(boolean condition, Date date, Date leftDate, String dateName, String leftDateName) {
            assertDateAfter(condition, date, leftDate, String.format("%s【%s】不能早于%s【%s】", dateName, dateFormat.format(date), leftDateName, dateFormat.format(leftDate)));
            return this;
        }

        public ParamsAssert notNull(Object val, String msg) {
            return notNull(true, val, msg);
        }

        public ParamsAssert notBlank(Object val, String msg) {
            return notBlank(true, val, msg);
        }


        public ParamsAssert dateBefore(Date date, Date rightDate, String dateName, String rightDateName) {
            return dateBefore(true, date, rightDate, dateName, rightDateName);
        }

        public ParamsAssert dateAfter(Date date, Date leftDate, String dateName, String leftDateName) {
            return dateAfter(true, date, leftDate, dateName, leftDateName);
        }
    }

    public static class ParamsCheck {
        private List<ValueCheck> nnVals;
        private List<ValueCheck> nbVals;
        private List<DateCheck> dates;

        private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

        public ParamsCheck() {
        }

        private void notNullInit() {
            nnVals = new ArrayList<>();
        }

        private void notBlankInit() {
            nbVals = new ArrayList<>();
        }

        private void dateInit() {
            dates = new ArrayList<>();
        }

        public ParamsCheck datePattern(String pattern) {
            this.dateFormat = new SimpleDateFormat(pattern);
            return this;
        }

        public ParamsCheck notNull(boolean condition, Object val, String msg) {
            if (!condition) {
                return this;
            }
            if (nnVals == null) {
                notNullInit();
            }
            nnVals.add(new ValueCheck(val, msg));
            return this;
        }

        public ParamsCheck notBlank(boolean condition, Object val, String msg) {
            if (!condition) {
                return this;
            }
            if (nbVals == null) {
                notBlankInit();
            }
            nbVals.add(new ValueCheck(val, msg));
            return this;
        }


        public ParamsCheck dateBefore(boolean condition, Date date, Date rightDate, String dateName, String rightDateName) {
            if (!condition) {
                return this;
            }
            if (dates == null) {
                dateInit();
            }
            dates.add(new DateCheck(date, null, rightDate, dateName, null, rightDateName, null));
            return this;
        }

        public ParamsCheck dateAfter(boolean condition, Date date, Date leftDate, String dateName, String leftDateName) {
            if (!condition) {
                return this;
            }
            if (dates == null) {
                dateInit();
            }
            dates.add(new DateCheck(date, leftDate, null, dateName, leftDateName, null, null));
            return this;
        }

        public ParamsCheck notNull(Object val, String nameOrMsg) {
            return notNull(true, val, nameOrMsg);
        }

        public ParamsCheck notBlank(Object val, String nameOrMsg) {
            return notBlank(true, val, nameOrMsg);
        }


        public ParamsCheck dateBefore(Date date, Date rightDate, String dateName, String rightDateName) {
            return dateBefore(true, date, rightDate, dateName, rightDateName);
        }

        public ParamsCheck dateAfter(Date date, Date leftDate, String dateName, String leftDateName) {
            return dateAfter(true, date, leftDate, dateName, leftDateName);
        }

        private ParamsCheck doAssert() {
            Optional.ofNullable(nnVals).ifPresent(vals -> {
                vals.forEach(v -> {
                    assertNotBlank(v.getVal(), v.getMsg());
                });
                vals.clear();
            });
            Optional.ofNullable(nbVals).ifPresent(vals -> {
                vals.forEach(v -> {
                    assertNotBlank(v.getVal(), v.getMsg());
                });
                vals.clear();
            });

            Optional.ofNullable(dates).ifPresent(ds -> {
                ds.forEach(d -> {
                    if (d.getDate()!=null && d.getRightDate() != null) {
                        assertDateBefore(d.getDate(), d.getRightDate(), String.format("【%s[%s]】不能晚于【%s[%s]】", d.getDateName(), dateFormat.format(d.getDate()), d.getRightDateName(), dateFormat.format(d.getRightDate())));
                    } else if (d.getDate()!=null && d.getLeftDate() != null) {
                        assertDateAfter(d.getDate(), d.getLeftDate(), String.format("【%s[%s]】不能早于【%s[%s]】", d.getDateName(), dateFormat.format(d.getDate()), d.getLeftDateName(), dateFormat.format(d.getLeftDate())));
                    }
                });
                ds.clear();
            });
            return this;
        }

        public String doCheck() {
            try {
                doAssert();
            } catch (GciBootException e) {
                return e.getMessage();
            }
            return null;
        }

    }
}
