package com.storlead.framework.mybatis.handler;

import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.storlead.framework.auth.vo.LoginUser;
import com.storlead.framework.common.constant.UserCacheKeyConstants;
import com.storlead.framework.core.context.Context;
import com.storlead.framework.core.tenant.TenantContext;
import com.storlead.framework.mybatis.tenant.TenantProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;

import java.util.Objects;

/**
 * 公共字段自动填充；tenant_id 仅对白名单表且实体含 tenantId 字段时写入。
 */
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {

    private final TenantProperties tenantProperties;

    public MyMetaObjectHandler(TenantProperties tenantProperties) {
        this.tenantProperties = tenantProperties;
    }

    @Override
    public void insertFill(MetaObject metaObject) {
        Object createTime = getFieldValByName("createTime", metaObject);
        if (Objects.isNull(createTime)) {
            DateTime time = new DateTime();
            this.setInsertFieldValByName("createTime", time, metaObject);
        }
        Object updateTime = getFieldValByName("updateTime", metaObject);
        if (Objects.isNull(updateTime)) {
            DateTime time = new DateTime();
            this.setUpdateFieldValByName("updateTime", time, metaObject);
        }
        if (Objects.isNull(Context.getContext())) {
            return;
        }
        LoginUser loginUser = Context.getContext().getAttribute(UserCacheKeyConstants.LOGIN_USER_INFO_KEY, LoginUser.class);
        Object createBy = getFieldValByName("createBy", metaObject);
        if (Objects.isNull(createBy)) {
            if (Objects.nonNull(loginUser)) {
                this.setInsertFieldValByName("createBy", loginUser.getId(), metaObject);
            }
        }
        Object ownerBy = getFieldValByName("ownerBy", metaObject);
        if (Objects.isNull(ownerBy)) {
            if (Objects.nonNull(loginUser)) {
                this.setInsertFieldValByName("ownerBy", loginUser.getId(), metaObject);
            }
        }
        if (metaObject.hasSetter("tenantId") && shouldFillTenantId(metaObject)) {
            Object tenantIdVal = getFieldValByName("tenantId", metaObject);
            if (Objects.isNull(tenantIdVal)) {
                Long tid = TenantContext.getTenantId();
                if (Objects.nonNull(tid)) {
                    this.setInsertFieldValByName("tenantId", tid, metaObject);
                }
            }
        }
        Object updateBy = getFieldValByName("updateBy", metaObject);
        if (Objects.isNull(updateBy)) {
            if (Objects.nonNull(loginUser)) {
                this.setInsertFieldValByName("updateBy", loginUser.getId(), metaObject);
            }
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        DateTime time = new DateTime();
        this.setUpdateFieldValByName("updateTime", time, metaObject);
        if (Objects.isNull(Context.getContext())) {
            return;
        }
        Object updateBy = getFieldValByName("updateBy", metaObject);
        LoginUser loginUser = Context.getContext().getAttribute(UserCacheKeyConstants.LOGIN_USER_INFO_KEY, LoginUser.class);
        if (Objects.isNull(updateBy)) {
            if (Objects.nonNull(loginUser)) {
                this.setInsertFieldValByName("updateBy", loginUser.getId(), metaObject);
            }
        }
    }

    private boolean shouldFillTenantId(MetaObject metaObject) {
        Object original = metaObject.getOriginalObject();
        if (original == null) {
            return false;
        }
        TableName tableName = original.getClass().getAnnotation(TableName.class);
        if (tableName == null || tableName.value().isEmpty()) {
            return false;
        }
        return tenantProperties.shouldApplyTenantLine(tableName.value());
    }
}
