package com.example.todolist.service;

import java.awt.Color;
import java.io.ByteArrayOutputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

import org.openpdf.text.Cell;
import org.openpdf.text.Document;
import org.openpdf.text.Font;
import org.openpdf.text.Paragraph;
import org.openpdf.text.Phrase;
import org.openpdf.text.Table;
import org.openpdf.text.alignment.HorizontalAlignment;
import org.openpdf.text.pdf.BaseFont;
import org.openpdf.text.pdf.PdfWriter;
import org.springframework.stereotype.Service;

import com.example.todolist.entity.Task;
import com.example.todolist.entity.Todo;

@Service
public class PdfService {
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 現在日時を含むサンプルPDFを生成する。
     *
     * @return 生成したPDFデータのバイト配列
     */
    public byte[] createSamplePdf() {
        LocalDateTime now = LocalDateTime.now();
        String currentTimeText = now.format(FORMATTER);
        Document doc = new Document();

        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            PdfWriter.getInstance(doc, baos);
            doc.open();

            // テキスト
            doc.add(new Paragraph(currentTimeText));
            // 表
            Table table = new Table(1);
            table.addCell("currentTime");
            table.addCell(currentTimeText);
            doc.add(table);

            doc.close();

            return baos.toByteArray();

        } catch (Exception e) {
            throw new IllegalStateException("Failed to generate PDF", e);

        } finally {
            if (doc.isOpen()) {
                doc.close();
            }
        }
    }

    /**
     * ToDo一覧をもとにPDFを生成する。
     *
     * @param todoList 出力対象のToDo一覧
     * @return 生成したPDFデータのバイト配列
     */
    public byte[] createTodoPdf(List<Todo> todoList) {
        if (todoList == null) {
            throw new IllegalArgumentException("todoList must not be null");
        }

        // PDFデータを格納するメモリ上の出力先
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // PDFドキュメントを表すオブジェクト。ここに文字や表を追加する。
        Document doc = new Document();

        try {
            //  このPDFはbaosに書き出す
            PdfWriter.getInstance(doc, baos);
            doc.open();

            // フォント定義
            BaseFont base = BaseFont.createFont(
                    "C:\\Windows\\Fonts\\msgothic.ttc,0",
                    BaseFont.IDENTITY_H,
                    BaseFont.NOT_EMBEDDED);
            Font font_g16_bold = new Font(base, 16, Font.BOLD);
            Font font_g12 = new Font(base, 12);
            Font font_g10 = new Font(base, 10);
            Font font_g12_underline = new Font(base, 11, Font.UNDERLINE);
            Font font_g10_red = new Font(base, 10);
            font_g10_red.setColor(new Color(255, 0, 0));

            // 見出しdocに追加
            doc.add(new Paragraph("ToDo List　", font_g16_bold));
            doc.add(new Paragraph("　", font_g16_bold));

            // 集計用カウンタ
            int numOfTodo = 0;
            int numOfDoneTodo = 0;
            int numOfTask = 0;
            int numOfDoneTask = 0;

            // Todo明細出力
            for (Todo todo : todoList) {
                ++numOfTodo;
                if ("Y".equals(todo.getDone())) {
                    ++numOfDoneTodo;
                }
                // ToDoを編集してdocに追加
                doc.add(new Paragraph(todo2paragraph(todo), font_g12));

                List<Task> taskList = todo.getTaskList();
                if (taskList != null) {
                    for (Task task : taskList) {
                        ++numOfTask;
                        if ("Y".equals(task.getDone())) {
                            ++numOfDoneTask;
                        }
                        // タスクを編集してdocに追加
                        doc.add(new Paragraph("  " + task2paragraph(task), font_g10));
                    }
                }
            }

            // 完了率計算
            int todoDoneRate = (numOfTodo > 0)
                    ? (int) ((float) numOfDoneTodo / (float) numOfTodo * 100)
                    : -1;

            int taskDoneRate = (numOfTask > 0)
                    ? (int) ((float) numOfDoneTask / (float) numOfTask * 100)
                    : -1;

            // 集計表の見出しをdocに追加
            doc.add(new Paragraph(" ", font_g12));
            doc.add(new Paragraph("　集計表　", font_g12_underline));

            // 表の定義(8列)
            Table summaryTable = new Table(8);
            // セル幅
            summaryTable.setWidth(100);
            // 罫線との余白
            summaryTable.setPadding(3);

            // 見出し行
            HorizontalAlignment hcenter = HorizontalAlignment.CENTER;
            summaryTable.addCell(makeCell("Todo数", font_g10, 0.9f, hcenter));
            summaryTable.addCell(makeCell("完了", font_g10, 0.9f, hcenter));
            summaryTable.addCell(makeCell("未完了", font_g10, 0.9f, hcenter));
            summaryTable.addCell(makeCell("完了率", font_g10, 0.9f, hcenter));
            summaryTable.addCell(makeCell("Task数", font_g10, 0.9f, hcenter));
            summaryTable.addCell(makeCell("完了", font_g10, 0.9f, hcenter));
            summaryTable.addCell(makeCell("未完了", font_g10, 0.9f, hcenter));
            summaryTable.addCell(makeCell("完了率", font_g10, 0.9f, hcenter));

            // 集計結果行
            //  Todo数
            summaryTable.addCell(makeCell(String.valueOf(numOfTodo), font_g10, 1.0f, hcenter));
            //  完了Todo数
            summaryTable.addCell(makeCell(String.valueOf(numOfDoneTodo), font_g10, 1.0f, hcenter));
            //  未完了Todo数
            summaryTable.addCell(makeCell(String.valueOf(numOfTodo - numOfDoneTodo), font_g10, 1.0f, hcenter));
            //  完了率
            summaryTable.addCell(makeCell(
                    (todoDoneRate < 0) ? "-" : (todoDoneRate + "%"),
                    font_g10_red,
                    1.0f,
                    hcenter));
            //  Task数
            summaryTable.addCell(makeCell(String.valueOf(numOfTask), font_g10, 1.0f, hcenter));
            //  完了Task数
            summaryTable.addCell(makeCell(String.valueOf(numOfDoneTask), font_g10, 1.0f, hcenter));
            //  未完了Task数
            summaryTable.addCell(makeCell(String.valueOf(numOfTask - numOfDoneTask), font_g10, 1.0f, hcenter));
            //  完了率
            summaryTable.addCell(makeCell(
                    (taskDoneRate < 0) ? "-" : (taskDoneRate + "%"),
                    font_g10_red,
                    1.0f,
                    hcenter));

            //  集計表をdocに追加
            doc.add(summaryTable);

            doc.close();

            //baosに格納したPDFデータをbyte型の配列(byte[])に変換してreturnする。
            return baos.toByteArray();

        } catch (Exception e) {
            throw new IllegalStateException("Failed to generate Todo PDF", e);

        } finally {
            if (doc.isOpen()) {
                doc.close();
            }
        }
    }

    /**
     * Cellオブジェクトを生成するユーティリティメソッド
     * 
     * @param content   出力する文字列
     * @param font      フォント
     * @param grayFill  網掛けの濃さ（0.0～1.0）
     * @param alignment 水平位置
     * @return Cellオブジェクト
     */
    private Cell makeCell(String content, Font font, float grayFill, HorizontalAlignment alignment) {
        // Cellオブジェクト生成
        Cell cell = new Cell(new Phrase(content, font));
        // 網掛け
        cell.setGrayFill(grayFill);
        // 水平位置
        cell.setHorizontalAlignment(alignment);
        return cell;
    }

    /**
     * Todoオブジェクトの内容をPDF出力用に文字列に編集して返す
     * 
     * @param todo 編集するTodoオブジェクト
     * @return 編集結果の文字列
     */
    private String todo2paragraph(Todo todo) {
        StringBuilder sb = new StringBuilder();

        sb.append("Y".equals(todo.getDone()) ? "■" : "□");
        sb.append(" ").append(todo.getTitle());
        sb.append(" ( ");
        sb.append("重要度： ").append(todo.getImportance() == 1 ? "★★★" : "★");
        sb.append(" / ");
        sb.append("緊急度： ").append(todo.getUrgency() == 1 ? "★★★" : "★");
        sb.append(" / ");
        sb.append(" 期限： ").append(todo.getDeadline() == null ? "-" : todo.getDeadline());
        sb.append(" )");

        return sb.toString();
    }

    /**
     * Taskオブジェクトの内容をPDF出力用に文字列に編集して返す
     * 
     * @param task 編集するtaskオブジェクト
     * @return 編集結果の文字列
     */
    private String task2paragraph(Task task) {
        StringBuilder sb = new StringBuilder();

        sb.append("Y".equals(task.getDone()) ? "■" : "□");
        sb.append(" ").append(task.getTitle());
        sb.append(" ( ");
        sb.append(" 期限： ").append(task.getDeadline() == null ? "-" : task.getDeadline());
        sb.append(" )");

        return sb.toString();
    }
}
