package com.schoolinout.web.controller.api;

import com.schoolinout.api.service.IApiParentService;
import com.schoolinout.api.service.IApiParentStudentRelationService;
import com.schoolinout.api.service.IApiStudentService;
import com.schoolinout.common.core.controller.BaseController;
import com.schoolinout.common.core.domain.AjaxResult;
import com.schoolinout.common.core.domain.entity.ParentLogin;
import com.schoolinout.common.core.domain.entity.SysDictData;
import com.schoolinout.common.core.domain.model.LoginUser;
import com.schoolinout.common.core.redis.RedisCache;
import com.schoolinout.common.exception.ServiceException;
import com.schoolinout.common.exception.user.UserPasswordNotMatchException;
import com.schoolinout.common.utils.StringUtils;
import com.schoolinout.common.validate.groups.Login;
import com.schoolinout.common.validate.groups.Save;
import com.schoolinout.framework.web.service.TokenService;
import com.schoolinout.system.domain.Parent;
import com.schoolinout.system.domain.ParentStudent;
import com.schoolinout.system.domain.Student;
import com.schoolinout.system.domain.dto.ApiParentDto;
import com.schoolinout.system.service.ISysDictTypeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author sakura
 * @date 2024/1/9 17:17:17 Tue
 */
@Tag(name = "用户端-家长接口")
@RequestMapping("/app/parent")
@RestController
public class Api_ParentController extends BaseController {

    public static final String CODE_CACHE_KEY = "validate:code:";

    @Resource(name = "parentLoginAuthenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    private IApiParentService parentService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private IApiStudentService studentService;
    @Autowired
    private IApiParentStudentRelationService relationService;

    @Autowired
    private ISysDictTypeService dictTypeService;

    @Autowired
    private RedisCache redisCache;

    @Operation(summary = "家长登入")
    @PostMapping("/login")
    public AjaxResult parentLogin(@Validated(Login.class) @RequestBody ApiParentDto form) {
        // step1：校验验证码是否正确
        boolean matches = form.getPhone().matches("^1[34578]\\d{9}$");
        if (!matches) {
            return AjaxResult.error("手机号输入格式不正确");
        }
        String cacheCode = redisCache.getCacheObject(form.getPhone());
        if (cacheCode == null || !cacheCode.equalsIgnoreCase(form.getCode())) {
            return AjaxResult.error("验证码输入错误");
        }
        // step2：通过手机号去查询家长
        Authentication authenticate;
        try {
            authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(form.getPhone(), form.getPhone()));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                throw new UserPasswordNotMatchException();
            } else {
                throw new ServiceException(e.getMessage());
            }
        }
        // step3：通过学号去查询学生
        Student selectConditionStu = new Student();
        selectConditionStu.setStudentNum(form.getStudentNum());
        Student student = studentService.listStudentSimple(selectConditionStu);
        if (student == null) {
            return AjaxResult.error("当前学号不存在学生");
        }
        // step4：查询当前学号是否跟当前家长绑定
        LoginUser principal = (LoginUser) authenticate.getPrincipal();
        ParentLogin parentLogin = principal.getParentLogin();
        ParentStudent parentStudent = relationService.listParentStudentSimple(parentLogin.getId(), student.getId());
        if (parentStudent == null) {
            return AjaxResult.success("当前家长未绑定有学号对应的学生", false);
        }
        // step5：返回登入成功的令牌
        String token = tokenService.createToken(principal);
        // 生成token
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("user", parentLogin);
        // TODO (sakura, 2024/1/10, 12:42, 数据脱敏)
        return AjaxResult.success("登入成功", map);
    }

    @Operation(summary = "家长注册")
    @PostMapping("/register")
    public AjaxResult parentRegister(@Validated(Save.class) @RequestBody ApiParentDto form) {
        // step1: 校验手机号是否正确
        boolean matches = form.getPhone().matches("^1[34578]\\d{9}$");
        if (!matches) {
            return AjaxResult.error("手机号输入格式不正确");
        }
        // step2：校验手机号是否存在用户
        Parent parent = new Parent();
        parent.setParentPhone(form.getPhone());
        parent = parentService.listParentSimple(parent);
        if (parent != null) {
            return AjaxResult.error("当前手机号已注册！");
        }
        // step3：校验要绑定的学号的学生是否存在
        Student student = new Student();
        student.setStudentNum(form.getStudentNum());
        student = studentService.listStudentSimple(student);
        if (student == null) {
            return AjaxResult.error("不存在该学号");
        }
        // step4：校验成功则添加对应的关系
        parent = new Parent();
        parent.setParentName(form.getName());
        parent.setParentPhone(form.getPhone());
        parent.setRelation(form.getRelation());
        parent.setStudentIds(String.valueOf(student.getId()));
        parentService.saveParent(parent);
        return AjaxResult.success("注册成功，请去登入！");
    }

    @Operation(summary = "发送手机号验证码")
    @PostMapping("/send/phone/code/{phone}")
    public AjaxResult sendPhoneCode(@PathVariable String phone) {
        boolean matches = phone.matches("^1[34578]\\d{9}$");
        if (!matches) {
            return AjaxResult.error("手机号输入格式不正确");
        }
        // 拼 key
        String cacheKey = CODE_CACHE_KEY + phone;
        // 发生验证码
        String code = RandomStringUtils.random(6, "0123456789");
        // 5 分钟有效时间
        redisCache.setCacheObject(cacheKey, code, 5, TimeUnit.MINUTES);
        return AjaxResult.success("短信验证码已发送，请注意查收！");
    }

    @Operation(summary = "获取家长与学生关系列表")
    @GetMapping("/list/relation")
    public AjaxResult searcherRelation() {
        List<SysDictData> data = dictTypeService.selectDictDataByType("parent_relation");
        if (StringUtils.isNull(data)) {
            data = new ArrayList<>();
        }
        return AjaxResult.success(data);
    }

    @Operation(summary = "新增绑定学生")
    @PostMapping("/bind/relation/{studentNum}")
    public AjaxResult bindStudent(@PathVariable String studentNum) {

        // step1：检测学号学生是否存在
        Student student = new Student();
        student.setStudentNum(studentNum);
        Student studentDb = studentService.listStudentSimple(student);
        if (studentDb == null) {
            return AjaxResult.error("不存在该学号的学生");
        }
        // step2：存在及保证关系
        Long parentId = getLoginUser().getParentLogin().getId();
        parentService.saveOrUpdateRelation(parentId, studentDb.getId());
        return success();
    }
}
