package com.lanyuanxiaoyao.bookstore.controller;

import cn.hutool.core.util.ObjectUtil;
import com.lanyuanxiaoyao.bookstore.entity.Chapter;
import com.lanyuanxiaoyao.bookstore.entity.Line;
import com.lanyuanxiaoyao.bookstore.entity.vo.Option;
import com.lanyuanxiaoyao.bookstore.service.BookService;
import com.lanyuanxiaoyao.bookstore.service.ChapterService;
import com.lanyuanxiaoyao.bookstore.service.LineService;
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("chapter")
public class ChapterController extends SimpleControllerSupport<Chapter, ChapterController.SaveItem, ChapterController.DetailItem, ChapterController.DetailItem> {
  private final ChapterService chapterService;
  private final BookService bookService;
  private final LineService lineService;

  public ChapterController(ChapterService service, BookService bookService, LineService lineService) {
    super(service);
    this.chapterService = service;
    this.bookService = bookService;
    this.lineService = lineService;
  }

  @GetMapping("chapters")
  public List<Option> chapters() {
    return chapterService.chapters();
  }

  @Transactional(rollbackFor = Throwable.class)
  @PostMapping("save_with_content")
  public GlobalResponse<Object> saveWithContent(@RequestBody SaveWithContentItem item) {
    if (SaveWithContentItem.Mode.CREATE.equals(item.mode())) {
      var chapter = new Chapter();
      chapter.setSequence(chapterService.latestSequence(item.bookId()) + 1);
      chapter.setName(item.name());
      chapter.setDescription(item.description());
      chapter.setBook(bookService.detailOrThrow(item.bookId()));
      var chapterId = chapterService.save(chapter);
      lineService.load(chapterId, item.content());
    } else if (SaveWithContentItem.Mode.OVERRIDE.equals(item.mode())) {
      var chapter = chapterService.detailOrThrow(item.id());
      chapter.setName(item.name());
      chapter.setDescription(item.description());
      var chapterId = chapterService.save(chapter);
      lineService.empty(chapterId);
      lineService.load(chapterId, item.content());
    } else {
      return GlobalResponse.responseError("Invalid mode");
    }
    return GlobalResponse.responseSuccess();
  }

  @GetMapping("content/{chapter_id}")
  public GlobalResponse<Map<String, Object>> content(@PathVariable("chapter_id") Long chapterId) {
    var chapter = chapterService.detailOrThrow(chapterId);
    return GlobalResponse.responseDetailData(
        chapter.getContent()
            .stream()
            .sorted(Comparator.comparing(Line::getSequence))
            .map(Line::getText)
            .collect(Collectors.joining("\n"))
    );
  }

  @GetMapping("generate_sequence")
  public GlobalResponse<Object> generateSequence() {
    chapterService.generateSequence();
    return GlobalResponse.responseSuccess();
  }

  @Override
  protected Function<SaveItem, Chapter> saveItemMapper() {
    return item -> {
      var chapter = new Chapter();
      chapter.setId(item.id());
      chapter.setSequence(ObjectUtil.defaultIfNull(item.sequence(), chapterService.latestSequence(item.bookId()) + 1));
      chapter.setName(item.name());
      chapter.setDescription(item.description());
      chapter.setBook(bookService.detailOrThrow(item.bookId()));
      return chapter;
    };
  }

  private DetailItem toDetailItem(Chapter chapter) {
    return new DetailItem(
        chapter.getId(),
        chapter.getSequence(),
        chapter.getName(),
        chapter.getDescription(),
        chapter.getCreatedTime(),
        chapter.getModifiedTime()
    );
  }

  @Override
  protected Function<Chapter, DetailItem> listItemMapper() {
    return this::toDetailItem;
  }

  @Override
  protected Function<Chapter, DetailItem> detailItemMapper() {
    return this::toDetailItem;
  }

  public record SaveItem(
      Long id,
      Long bookId,
      Double sequence,
      String name,
      String description
  ) {
  }

  public record SaveWithContentItem(
      Long id,
      Long bookId,
      String name,
      String description,
      Mode mode,
      String content
  ) {
    public enum Mode {
      CREATE, OVERRIDE
    }
  }

  public record DetailItem(
      Long id,
      Double sequence,
      String name,
      String description,
      LocalDateTime createdTime,
      LocalDateTime modifiedTime
  ) {
  }
}

