package com.mzh.library.service.impl;

import com.mzh.library.dao.ReaderDao;
import com.mzh.library.entity.AuthenticatedUser;
import com.mzh.library.entity.Permission;
import com.mzh.library.entity.Reader;
import com.mzh.library.entity.ReaderSearchCriteria;
import com.mzh.library.entity.ReaderStatus;
import com.mzh.library.exception.DaoException;
import com.mzh.library.service.PermissionPolicy;
import com.mzh.library.service.ReaderService;
import com.mzh.library.service.ServiceResult;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ReaderServiceImpl implements ReaderService {
    private static final Logger LOGGER = Logger.getLogger(ReaderServiceImpl.class.getName());
    private static final String UNAVAILABLE_MESSAGE =
        "读者服务暂时不可用，请稍后重试。";
    private static final String VALIDATION_MESSAGE = "请修正高亮的读者字段。";
    private static final String SEARCH_VALIDATION_MESSAGE = "请修正读者检索筛选条件。";
    private static final String DENIED_MESSAGE = "您无权管理读者。";
    private static final int MAX_BORROW_LIMIT = 50;
    private static final Pattern PHONE_PATTERN = Pattern.compile("(?=.*\\d)[0-9+()\\-\\s]{6,32}");
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$");

    private final ReaderDao readerDao;
    private final PermissionPolicy permissionPolicy;

    public ReaderServiceImpl(ReaderDao readerDao) {
        this(readerDao, new PermissionPolicy());
    }

    public ReaderServiceImpl(ReaderDao readerDao, PermissionPolicy permissionPolicy) {
        this.readerDao = readerDao;
        this.permissionPolicy = permissionPolicy;
    }

    @Override
    public ServiceResult<List<Reader>> searchReaders(ReaderSearchCriteria criteria) {
        ReaderSearchCriteria normalized = criteria == null ? new ReaderSearchCriteria() : criteria;
        Map<String, String> errors = validateSearch(normalized);
        if (!errors.isEmpty()) {
            return ServiceResult.validationFailure(SEARCH_VALIDATION_MESSAGE, errors);
        }

        try {
            return ServiceResult.success(readerDao.search(normalized));
        } catch (DaoException ex) {
            LOGGER.log(Level.SEVERE, "Unable to search readers", ex);
            return ServiceResult.failure(UNAVAILABLE_MESSAGE);
        }
    }

    @Override
    public ServiceResult<Optional<Reader>> findReader(long id) {
        if (id <= 0) {
            return ServiceResult.failure("请选择有效的读者。");
        }

        try {
            return ServiceResult.success(readerDao.findById(id));
        } catch (DaoException ex) {
            LOGGER.log(Level.SEVERE, "Unable to load reader id=" + id, ex);
            return ServiceResult.failure(UNAVAILABLE_MESSAGE);
        }
    }

    @Override
    public ServiceResult<Long> createReader(AuthenticatedUser actor, Reader reader) {
        if (!canManageReaders(actor)) {
            return ServiceResult.failure(DENIED_MESSAGE);
        }

        normalize(reader);
        Map<String, String> errors = validate(reader, false);
        if (!errors.isEmpty()) {
            return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
        }

        try {
            if (readerDao.findByIdentifier(reader.getIdentifier()).isPresent()) {
                errors.put("identifier", "读者编号已被使用。");
                return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
            }
            if (reader.getUserId() != null && readerDao.findByUserId(reader.getUserId()).isPresent()) {
                errors.put("userId", "关联账户已绑定到其他读者档案。");
                return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
            }

            long id = readerDao.create(reader);
            LOGGER.info("Created reader id=" + id + " actorId=" + actor.getId());
            return ServiceResult.success(id, "读者档案已创建。");
        } catch (DaoException ex) {
            LOGGER.log(Level.SEVERE, "Unable to create reader actorId=" + actor.getId(), ex);
            return ServiceResult.failure(UNAVAILABLE_MESSAGE);
        }
    }

    @Override
    public ServiceResult<Void> updateReader(AuthenticatedUser actor, Reader reader) {
        if (!canManageReaders(actor)) {
            return ServiceResult.failure(DENIED_MESSAGE);
        }

        normalize(reader);
        Map<String, String> errors = validate(reader, true);
        if (!errors.isEmpty()) {
            return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
        }

        try {
            Optional<Reader> existingWithIdentifier = readerDao.findByIdentifier(reader.getIdentifier());
            if (existingWithIdentifier.isPresent() && existingWithIdentifier.get().getId() != reader.getId()) {
                errors.put("identifier", "读者编号已被使用。");
                return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
            }
            if (reader.getUserId() != null) {
                Optional<Reader> existingWithUser = readerDao.findByUserId(reader.getUserId());
                if (existingWithUser.isPresent() && existingWithUser.get().getId() != reader.getId()) {
                    errors.put("userId", "关联账户已绑定到其他读者档案。");
                    return ServiceResult.validationFailure(VALIDATION_MESSAGE, errors);
                }
            }

            if (!readerDao.update(reader)) {
                return ServiceResult.failure("未找到读者档案。");
            }

            LOGGER.info("Updated reader id=" + reader.getId() + " actorId=" + actor.getId());
            return ServiceResult.success(null, "读者档案已更新。");
        } catch (DaoException ex) {
            LOGGER.log(Level.SEVERE, "Unable to update reader id=" + reader.getId() + " actorId=" + actor.getId(), ex);
            return ServiceResult.failure(UNAVAILABLE_MESSAGE);
        }
    }

    @Override
    public ServiceResult<Void> deactivateReader(AuthenticatedUser actor, long id) {
        if (!canManageReaders(actor)) {
            return ServiceResult.failure(DENIED_MESSAGE);
        }
        if (id <= 0) {
            return ServiceResult.failure("请选择有效的读者。");
        }

        try {
            if (!readerDao.deactivate(id)) {
                return ServiceResult.failure("未找到读者档案。");
            }

            LOGGER.info("Deactivated reader id=" + id + " actorId=" + actor.getId());
            return ServiceResult.success(null, "读者档案已停用。");
        } catch (DaoException ex) {
            LOGGER.log(Level.SEVERE, "Unable to deactivate reader id=" + id + " actorId=" + actor.getId(), ex);
            return ServiceResult.failure(UNAVAILABLE_MESSAGE);
        }
    }

    private boolean canManageReaders(AuthenticatedUser actor) {
        return actor != null && permissionPolicy.allows(actor.getRole(), Permission.MANAGE_READERS);
    }

    private void normalize(Reader reader) {
        if (reader == null) {
            return;
        }
        reader.setIdentifier(trim(reader.getIdentifier()));
        reader.setFullName(trim(reader.getFullName()));
        reader.setPhone(trim(reader.getPhone()));
        reader.setEmail(trim(reader.getEmail()));
    }

    private Map<String, String> validateSearch(ReaderSearchCriteria criteria) {
        Map<String, String> errors = new LinkedHashMap<>();
        if (criteria.getStatusCode() != null && !criteria.getStatusCode().isEmpty()) {
            try {
                criteria.setStatusCode(ReaderStatus.fromCode(criteria.getStatusCode()).getCode());
            } catch (IllegalArgumentException ex) {
                errors.put("status", "请选择有效的状态。");
            }
        }
        return errors;
    }

    private Map<String, String> validate(Reader reader, boolean requireId) {
        Map<String, String> errors = new LinkedHashMap<>();
        if (reader == null) {
            errors.put("reader", "请填写读者详情。");
            return errors;
        }

        if (requireId && reader.getId() <= 0) {
            errors.put("id", "请选择有效的读者。");
        }
        requireLength(errors, "identifier", reader.getIdentifier(), "读者编号", 64);
        requireLength(errors, "fullName", reader.getFullName(), "姓名", 100);
        if (reader.getUserId() != null && reader.getUserId() <= 0) {
            errors.put("userId", "关联账户 ID 必须为正数。");
        }
        validateContact(errors, reader);
        if (reader.getStatus() == null) {
            errors.put("status", "请选择状态。");
        }
        if (reader.getMaxBorrowCount() < 1 || reader.getMaxBorrowCount() > MAX_BORROW_LIMIT) {
            errors.put("maxBorrowCount", "最大借阅数量必须在 1 到 " + MAX_BORROW_LIMIT + " 之间。");
        }
        return errors;
    }

    private void validateContact(Map<String, String> errors, Reader reader) {
        String phone = reader.getPhone();
        String email = reader.getEmail();
        if ((phone == null || phone.isEmpty()) && (email == null || email.isEmpty())) {
            errors.put("phone", "请填写电话或邮箱。");
            return;
        }
        if (phone != null && !phone.isEmpty() && !PHONE_PATTERN.matcher(phone).matches()) {
            errors.put("phone", "电话必须包含数字，并使用 6 到 32 位数字或常见电话符号。");
        }
        if (email != null && !email.isEmpty() && !EMAIL_PATTERN.matcher(email).matches()) {
            errors.put("email", "邮箱格式不正确。");
        }
    }

    private void requireLength(Map<String, String> errors, String field, String value, String label, int maxLength) {
        if (value == null || value.isEmpty()) {
            errors.put(field, "请填写" + label + "。");
            return;
        }
        if (value.length() > maxLength) {
            errors.put(field, label + "不能超过 " + maxLength + " 个字符。");
        }
    }

    private String trim(String value) {
        return value == null ? "" : value.trim();
    }
}
