package com.mingzuozhibi.modules.disc;

import com.mingzuozhibi.commons.base.BaseController;
import com.mingzuozhibi.commons.base.BaseKeys.Name;
import com.mingzuozhibi.commons.logger.LoggerBind;
import com.mingzuozhibi.modules.disc.Disc.DiscType;
import com.mingzuozhibi.modules.record.RecordService;
import com.mingzuozhibi.modules.spider.HistoryRepository;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.time.LocalDate;
import java.util.Objects;

import static com.mingzuozhibi.commons.utils.MyTimeUtils.fmtDate;
import static com.mingzuozhibi.modules.disc.DiscUtils.updateRank;
import static com.mingzuozhibi.support.ChecksUtils.*;
import static com.mingzuozhibi.support.ModifyUtils.*;

@RestController
@LoggerBind(Name.SERVER_USER)
public class DiscController extends BaseController {

    @Autowired
    private RecordService recordService;

    @Autowired
    private DiscRepository discRepository;

    @Autowired
    private HistoryRepository historyRepository;

    @Transactional
    @GetMapping(value = "/api/discs/{id}", produces = MEDIA_TYPE)
    public String findById(@PathVariable Long id) {
        var byId = discRepository.findById(id);
        if (byId.isEmpty()) {
            return paramNotExists("碟片ID");
        }
        return dataResult(byId.get().toJson());
    }

    @Transactional
    @GetMapping(value = "/api/discs/asin/{asin}", produces = MEDIA_TYPE)
    public String findByAsin(@PathVariable String asin) {
        var byAsin = discRepository.findByAsin(asin);
        if (byAsin.isEmpty()) {
            return paramNotExists("碟片ASIN");
        }
        return dataResult(byAsin.get().toJson());
    }

    @Transactional
    @GetMapping(value = "/api/discs/{id}/records", produces = MEDIA_TYPE)
    public String findRecords(@PathVariable Long id) {
        var byId = discRepository.findById(id);
        if (byId.isEmpty()) {
            return paramNotExists("碟片ID");
        }
        var disc = byId.get();
        var object = gson.toJsonTree(disc).getAsJsonObject();
        object.add("records", recordService.buildDiscRecords(disc));
        return dataResult(object);
    }

    @Setter
    private static class CreateForm {
        private String asin;
        private String title;
        private DiscType discType;
        private String releaseDate;
    }

    @Transactional
    @PreAuthorize("hasRole('BASIC')")
    @PostMapping(value = "/api/discs", produces = MEDIA_TYPE)
    public String doCreate(@RequestBody CreateForm form) {
        var checks = runChecks(
            checkNotEmpty(form.asin, "ASIN"),
            checkStrMatch(form.asin, "ASIN", "[A-Z0-9]{10}"),
            checkNotEmpty(form.discType, "碟片类型"),
            checkNotEmpty(form.releaseDate, "发售日期"),
            checkStrMatch(form.releaseDate, "发售日期", "\\d{4}/\\d{1,2}/\\d{1,2}")
        );
        if (checks.isPresent()) {
            return errorResult(checks.get());
        }
        if (StringUtils.isEmpty(form.title)) {
            form.title = form.asin;
        }
        if (discRepository.existsByAsin(form.asin)) {
            return paramExists("ASIN");
        }
        var localDate = LocalDate.parse(form.releaseDate, fmtDate);
        var disc = new Disc(form.asin, form.title, form.discType, localDate);
        discRepository.save(disc);
        historyRepository.setTracked(form.asin, true);
        bind.success(logCreate("碟片(手动)", disc.getLogName(), disc.toJson().toString()));
        return dataResult(disc.toJson());
    }

    @Setter
    private static class UpdateForm {
        private String titlePc;
        private DiscType discType;
        private String releaseDate;
    }

    @Transactional
    @PreAuthorize("hasRole('BASIC')")
    @PutMapping(value = "/api/discs/{id}", produces = MEDIA_TYPE)
    public String doUpdate(@PathVariable Long id,
                           @RequestBody UpdateForm form) {
        var checks = runChecks(
            checkNotEmpty(form.discType, "碟片类型"),
            checkNotEmpty(form.releaseDate, "发售日期"),
            checkStrMatch(form.releaseDate, "发售日期", "\\d{4}/\\d{1,2}/\\d{1,2}")
        );
        if (checks.isPresent()) {
            return errorResult(checks.get());
        }
        var localDate = LocalDate.parse(form.releaseDate, fmtDate);
        var byId = discRepository.findById(id);
        if (byId.isEmpty()) {
            return paramNotExists("碟片ID");
        }
        var disc = byId.get();
        if (!Objects.equals(disc.getTitlePc(), form.titlePc)) {
            bind.info(logUpdate("碟片标题", disc.getTitlePc(), form.titlePc, disc.getLogName()));
            disc.setTitlePc(form.titlePc);
        }
        if (!Objects.equals(disc.getDiscType(), form.discType)) {
            bind.notify(logUpdate("碟片类型", disc.getDiscType(), form.discType, disc.getLogName()));
            disc.setDiscType(form.discType);
        }
        if (!Objects.equals(disc.getReleaseDate(), localDate)) {
            bind.notify(logUpdate("发售日期", disc.getReleaseDate(), localDate, disc.getLogName()));
            disc.setReleaseDate(localDate);
        }
        return dataResult(disc.toJson());
    }

    private static class PatchForm {
        Integer rank;
    }

    @Transactional
    @PreAuthorize("hasRole('BASIC')")
    @PatchMapping(value = "/api/discs/{id}", produces = MEDIA_TYPE)
    public String doPatch(@PathVariable Long id, @RequestBody PatchForm form) {
        var byId = discRepository.findById(id);
        if (byId.isEmpty()) {
            return paramNotExists("碟片ID");
        }
        var disc = byId.get();
        if (form.rank != null && !(Objects.equals(form.rank, disc.getThisRank()))) {
            updateRank(disc, form.rank, Instant.now());
            amqpSender.bind(Name.DEFAULT).debug(logUpdate("碟片排名",
                disc.getPrevRank(), disc.getThisRank(), disc.getLogName()));
        }
        return dataResult(disc.toJson());
    }

}

@@ -5409,24 +5409,36 @@
 ());%0A    %7D%0A%0A
+    @Setter%0A
     private 

Add @Setter to PatchForm