package com.lanyuanxiaoyao.bookstore.controller;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.lanyuanxiaoyao.bookstore.entity.Book;
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.service.template.controller.SimpleControllerSupport;
import jakarta.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("book")
public class BookController extends SimpleControllerSupport<Book, BookController.SaveItem, BookController.DetailItem, BookController.DetailItem> {
  private final BookService bookService;

  public BookController(BookService service) {
    super(service);
    this.bookService = service;
  }

  @GetMapping("tags")
  public List<Option> tags() {
    return bookService.tags();
  }

  @GetMapping("export/{book_id}")
  public void export(@PathVariable("book_id") Long bookId, HttpServletResponse response) throws IOException {
    var book = bookService.detailOrThrow(bookId);
    var result = new StringBuilder();
    result.append(StrUtil.format("""
        书名：{}
        作者：{}
        简介：{}
        来源：{}
        
        """, book.getName(), book.getAuthor(), book.getDescription(), book.getSource()));
    book.getChapters()
        .stream()
        .sorted(Comparator.comparing(Chapter::getSequence))
        .forEach(chapter -> {
          result.append(StrUtil.format("第{}章 {}", chapter.getSequence(), chapter.getName()));
          result.append("\n\n");
          chapter.getContent()
              .stream()
              .sorted(Comparator.comparing(Line::getSequence))
              .forEach(line -> {
                result.append(line.getText());
                result.append("\n");
              });
          result.append("\n\n");
        });
    response.setHeader("Access-Control-Expose-Headers", "Content-Type");
    response.setHeader("Content-Type", "text/plain");
    response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
    response.setHeader("Content-Disposition", StrUtil.format("attachment; filename={}", URLUtil.encodeAll(StrUtil.format("{}.txt", book.getName()))));
    IoUtil.copy(new ByteArrayInputStream(result.toString().getBytes()), response.getOutputStream());
  }

  @Override
  protected Function<SaveItem, Book> saveItemMapper() {
    return item -> {
      Book book = new Book();
      book.setId(item.id());
      book.setName(item.name());
      book.setAuthor(item.author());
      book.setDescription(item.description());
      book.setSource(item.source());
      book.setTags(item.tags());
      return book;
    };
  }

  private DetailItem toDetailItem(Book book) {
    return new DetailItem(
        book.getId(),
        book.getName(),
        book.getAuthor(),
        book.getDescription(),
        book.getSource(),
        book.getTags(),
        book.getCreatedTime(),
        book.getModifiedTime()
    );
  }

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

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

  public record SaveItem(
      Long id,
      String name,
      String author,
      String description,
      String source,
      Set<String> tags
  ) {
  }

  public record DetailItem(
      Long id,
      String name,
      String author,
      String description,
      String source,
      Set<String> tags,
      LocalDateTime createdTime,
      LocalDateTime modifiedTime
  ) {
  }
}

