package com.caliverse.admin.global.component.manager;

import com.caliverse.admin.domain.dao.admin.*;
import com.caliverse.admin.domain.dao.total.WalletUserMapper;
import com.caliverse.admin.domain.entity.*;
import com.caliverse.admin.domain.request.*;
import com.caliverse.admin.global.common.utils.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;

@Component
@Slf4j
public class BeforeDataResolver {
    private final AdminMapper adminMapper;
    private final MenuMapper menuMapper;
    private final LandMapper landMapper;
    private final BattleMapper battleMapper;
    private final BlackListMapper blackListMapper;
    private final CaliumMapper caliumMapper;
    private final EventMapper eventMapper;
    private final GroupMapper groupMapper;
    private final MailMapper mailMapper;
    private final NoticeMapper noticeMapper;
    private final DataMapper dataMapper;

    public BeforeDataResolver(@Lazy AdminMapper adminMapper,
                              @Lazy MenuMapper menuMapper,
                              @Lazy LandMapper landMapper,
                              @Lazy BattleMapper battleMapper,
                              @Lazy BlackListMapper blackListMapper,
                              @Lazy CaliumMapper caliumMapper,
                              @Lazy EventMapper eventMapper,
                              @Lazy GroupMapper groupMapper,
                              @Lazy MailMapper mailMapper,
                              @Lazy NoticeMapper noticeMapper,
                              @Lazy DataMapper dataMapper
    ) {
        this.adminMapper = adminMapper;
        this.menuMapper = menuMapper;
        this.landMapper = landMapper;
        this.battleMapper = battleMapper;
        this.blackListMapper = blackListMapper;
        this.caliumMapper = caliumMapper;
        this.eventMapper = eventMapper;
        this.groupMapper = groupMapper;
        this.mailMapper = mailMapper;
        this.noticeMapper = noticeMapper;
        this.dataMapper = dataMapper;
    }

    private static final Map<String, Function<BeforeDataResolver, BiFunction<String, Object, Object>>> RESOLVER_MAP = Map.ofEntries(
            Map.entry("AdminMapper", resolver -> resolver::resolveAdminBeforeData),
            Map.entry("MenuMapper", resolver -> resolver::resolveBannerBeforeData),
            Map.entry("BattleMapper", resolver -> resolver::resolveBattleBeforeData),
            Map.entry("BlackListMapper", resolver -> resolver::resolveBlackListBeforeData),
            Map.entry("CaliumMapper", resolver -> resolver::resolveCaliumBeforeData),
            Map.entry("EventMapper", resolver -> resolver::resolveEventBeforeData),
            Map.entry("MailMapper", resolver -> resolver::resolveMailBeforeData),
            Map.entry("NoticeMapper", resolver -> resolver::resolveNoticeBeforeData),
            Map.entry("LandMapper", resolver -> resolver::resolveLandBeforeData),
            Map.entry("DataMapper", resolver -> resolver::resolveDataBeforeData),
            Map.entry("GroupMapper", resolver -> resolver::resolveGroupBeforeData)
    );

    public Object resolveBeforeData(String sqlId, Object parameter) {
        try {
            return RESOLVER_MAP.entrySet().stream()
                    .filter(entry -> sqlId.contains(entry.getKey()))
                    .findFirst()
                    .map(entry -> entry.getValue().apply(this).apply(sqlId, parameter))
                    .orElse(null);

        } catch (Exception e) {
            log.warn("Failed to resolve before data for {}: {}", sqlId, e.getMessage());
            return null;
        }
    }

    private Object resolveGroupBeforeData(String sqlId, Object parameter) {
        if(sqlId.contains("postGroup") || sqlId.contains("deleteGroup")){
            if (parameter instanceof Map) {
                Map<String, Object> params = (Map<String, Object>) parameter;

                if (params.containsKey("groupId")) {
                    return groupMapper.getGroupInfo(Long.parseLong((String) params.get("groupId")));
                }
            }

            if (parameter instanceof GroupRequest params) {
                return groupMapper.getGroupInfo(params.getId());
            }

            if(parameter instanceof Long id){
                return groupMapper.getGroupInfo(id);
            }
        }

        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("groupId")) {
                return groupMapper.getGroupAuth(Long.parseLong((String) params.get("groupId")));
            }
        }

        if (parameter instanceof GroupRequest params) {
            return groupMapper.getGroupAuth(params.getId());
        }

        if(parameter instanceof Long id){
            return groupMapper.getGroupAuth(id);
        }

        if(parameter instanceof String id){
            return groupMapper.getGroupAuth(Long.parseLong(id));
        }

        return null;
    }

    private Object resolveDataBeforeData(String sqlId, Object parameter) {
        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("id")) {
                return dataMapper.getDataInitDetail((Long) params.get("id"));
            }
        }

        if (parameter instanceof DataRequest params) {
            return dataMapper.getDataInitDetail(params.getId());
        }

        if(parameter instanceof Long id){
            return dataMapper.getDataInitDetail(id);
        }

        return null;
    }

    private Object resolveLandBeforeData(String sqlId, Object parameter) {
        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("id")) {
                if(sqlId.contains("LandOwnerChange")){
                    return landMapper.getLandOwnerChangeDetail((Long) params.get("id"));
                }
                return landMapper.getLandAuctionDetail((Long) params.get("id"));
            }
        }

        if (parameter instanceof LandRequest params) {
            if(sqlId.contains("LandOwnerChange")){
                return landMapper.getLandOwnerChangeDetail(params.getId());
            }
            return landMapper.getLandAuctionDetail(params.getId());
        }

        if(parameter instanceof Long id){
            if(sqlId.contains("LandOwnerChange")){
                return landMapper.getLandOwnerChangeDetail(id);
            }
            return landMapper.getLandAuctionDetail(id);
        }

        return null;
    }

    private Object resolveAdminBeforeData(String sqlId, Object parameter) {

        if(sqlId.contains("initPwd") || sqlId.contains("updatePwd")) {
            if (parameter instanceof AuthenticateRequest params) {
                String email = params.getEmail() == null ? CommonUtils.getAdmin().getEmail() : params.getEmail();
                return adminMapper.findByEmail(email).get();
            }
            if (parameter instanceof Map) {
                Map<String, Object> params = (Map<String, Object>) parameter;

                if (params.containsKey("id")) {
                    return adminMapper.findById((Long) params.get("id")).get();
                }
                Long id = CommonUtils.getAdmin().getId();
                if (id != null) {
                    return adminMapper.findById(id).get();
                }
            }
        }

        if(sqlId.contains("updateStatus") || sqlId.contains("updateGroup") || sqlId.contains("deleteAdmin")) {
            if (parameter instanceof AdminRequest params) {
                String email = params.getList().get(0).getEmail() == null ? CommonUtils.getAdmin().getEmail() : params.getList().get(0).getEmail();
                return adminMapper.findByEmail(email).get();
            }
            if (parameter instanceof Map) {
                Map<String, Object> params = (Map<String, Object>) parameter;

                if (params.containsKey("email")) {
                    return adminMapper.findByEmail((String) params.get("email")).get();
                }
            }
        }

        if(sqlId.contains("save")){
            if(parameter instanceof Admin params){
                return adminMapper.findByEmail(params.getEmail()).get();
            }
        }

        return null;
    }

    private Object resolveBannerBeforeData(String sqlId, Object parameter) {
        if (sqlId.contains("insertBanner")) {
            return null;
        }

        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("id")) {
                MenuBanner info = menuMapper.getBannerDetail((Long) params.get("id"));
                if(info != null){
                    info.setImageList(menuMapper.getMessage((Long) params.get("id")));
                }
                return info;
            }
        }

        if (parameter instanceof MenuRequest params) {
            MenuBanner info =menuMapper.getBannerDetail(params.getId());
            if(info != null) {
                info.setImageList(menuMapper.getMessage(params.getId()));
            }
            return info;
        }

        return null;
    }

    private Object resolveBattleBeforeData(String sqlId, Object parameter) {
        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("id")) {
                return battleMapper.getBattleEventDetail((Long) params.get("id"));
            }
        }

        if (parameter instanceof BattleEventRequest params) {
            return battleMapper.getBattleEventDetail(params.getId());
        }

        return null;
    }

    private Object resolveBlackListBeforeData(String sqlId, Object parameter) {
        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("id")) {
                return blackListMapper.getBlackListDetail((Long) params.get("id"));
            }
        }

        if (parameter instanceof BlackListRequest params) {
            return blackListMapper.getBlackListDetail(params.getId());
        }

        return null;
    }

    private Object resolveCaliumBeforeData(String sqlId, Object parameter) {
        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("id")) {
                return caliumMapper.getCaliumRequestDetail((Long) params.get("id"));
            }
        }

        if (parameter instanceof CaliumRequest params) {
            return caliumMapper.getCaliumRequestDetail(params.getId());
        }

        return null;
    }

    private Object resolveEventBeforeData(String sqlId, Object parameter) {
        if (sqlId.contains("postEvent") || sqlId.contains("updateEvent")) {
            return null;
        }

        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("id")) {
                Long id = (Long) params.get("id");
                Event event = eventMapper.getEventDetail(id);
                event.setMailList(eventMapper.getMessage(id));
                event.setItemList(eventMapper.getItem(id));
                return event;
            }
        }

        if (parameter instanceof EventRequest params) {
            Long id = params.getId();
            Event event = eventMapper.getEventDetail(id);
            event.setMailList(eventMapper.getMessage(id));
            event.setItemList(eventMapper.getItem(id));
            return event;
        }

        return null;
    }

    private Object resolveMailBeforeData(String sqlId, Object parameter) {
        if (sqlId.contains("postMail") || sqlId.contains("updateMail")) {
            return null;
        }

        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("id")) {
                Long id = (Long) params.get("id");
                Mail mail = mailMapper.getMailDetail(id);
                mail.setMailList(mailMapper.getMessage(id));
                mail.setItemList(mailMapper.getItem(id));
                return mail;
            }
        }

        if (parameter instanceof MailRequest params) {
            Long id = params.getId();
            Mail mail = mailMapper.getMailDetail(id);
            mail.setMailList(mailMapper.getMessage(id));
            mail.setItemList(mailMapper.getItem(id));
            return mail;
        }

        return null;
    }

    private Object resolveNoticeBeforeData(String sqlId, Object parameter) {
        if (sqlId.contains("postNotice") || sqlId.contains("updateNotice")) {
            return null;
        }

        if (parameter instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) parameter;

            if (params.containsKey("id")) {
                Long id = (Long) params.get("id");
                InGame notice = noticeMapper.getNoticeDetail(id);
                notice.setMessageList(noticeMapper.getMessage(id));
                return notice;
            }
        }

        if (parameter instanceof NoticeRequest params) {
            Long id = params.getId();
            InGame notice = noticeMapper.getNoticeDetail(id);
            notice.setMessageList(noticeMapper.getMessage(id));
            return notice;
        }

        if(parameter instanceof Long id){
            InGame notice = noticeMapper.getNoticeDetail(id);
            notice.setMessageList(noticeMapper.getMessage(id));
            return notice;
        }

        return null;
    }
}
