package com.example.todolist.service;

import java.time.DateTimeException;
import java.time.LocalDate;
import java.util.List;
import java.util.Locale;

import org.springframework.context.MessageSource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import com.example.todolist.common.Utils;
import com.example.todolist.entity.Todo;
import com.example.todolist.form.TaskData;
import com.example.todolist.form.TodoData;
import com.example.todolist.form.TodoQuery;
import com.example.todolist.repository.TodoRepository;

import lombok.AllArgsConstructor;

@Service
@AllArgsConstructor
public class TodoService {
    private final MessageSource messageSource;
    private final TodoRepository todoRepository;

    //  入力されたTodo/Taskのチェック
    public boolean isValid(TodoData todoData, BindingResult result, boolean isCreate, Locale locale) {
        boolean ans = true;
        // Todo 部分のチェック
        // 件名が全角スペースだけで構成されていたらエラー
        String title = todoData.getTitle();
        if (title != null && !title.equals("")) {
            boolean isAllDoubleSpace = true;
            for (int i = 0; i < title.length(); i++) {
                if (title.charAt(i) != '　') {
                    isAllDoubleSpace = false;
                    break;
                }
            }
            if (isAllDoubleSpace) {
                FieldError fieldError = new FieldError(
                        result.getObjectName(),
                        "title",
                        messageSource.getMessage("DoubleSpace.todoData.title", null, locale));
                result.addError(fieldError);
                ans = false;
            }
        }

        // 期限が過去日付ならエラー
        String deadline = todoData.getDeadline();
        if (!deadline.equals("")) {
            LocalDate tody = LocalDate.now();
            try {
                LocalDate deadlineDate = LocalDate.parse(deadline);
                //過去日付チェックは新規登録の場合のみ
                if (isCreate) {
                    if (deadlineDate.isBefore(tody)) {
                        FieldError fieldError = new FieldError(
                                result.getObjectName(),
                                "deadline",
                                messageSource.getMessage("Past.todoData.deadline", null, locale));
                        result.addError(fieldError);
                        ans = false;
                    }
                }
            } catch (DateTimeException e) {
                //	/ yyyy-mm-dd 形式チェック
                FieldError fieldError = new FieldError(
                        result.getObjectName(),
                        "deadline",
                        messageSource.getMessage("InvalidFormat.todoData.deadline", null, locale));
                result.addError(fieldError);
                ans = false;
            }
        }
        // Task のチェック(追加 ここから↓↓↓)
        List<TaskData> taskList = todoData.getTaskList();
        if (taskList != null) {
            // すべてのタスクに対して以下を実行する
            // 「タスクの n 番目」という情報が必要なので(拡張 for 文でなく)for 文を使用する
            for (int n = 0; n < taskList.size(); n++) {
                TaskData taskData = taskList.get(n);
                // タスクの件名が全角スペースだけで構成されていたらエラー
                if (!Utils.isBlank(taskData.getTitle())) {
                    if (Utils.isAllDoubleSpace(taskData.getTitle())) {
                        FieldError fieldError = new FieldError(
                                result.getObjectName(),
                                "taskList[" + n + "].title",
                                messageSource.getMessage(
                                        "DoubleSpace.todoData.title", null, locale));
                        result.addError(fieldError);
                        ans = false;
                    }
                }
                // タスク期限の yyyy-mm-dd 形式チェック
                String taskDeadline = taskData.getDeadline();
                if (!taskDeadline.equals("") && !Utils.isValidDateFormat(taskDeadline)) {
                    FieldError fieldError = new FieldError(
                            result.getObjectName(),
                            "taskList[" + n + "].deadline",
                            messageSource.getMessage(
                                    "InvalidFormat.todoData.deadline", null, locale));
                    result.addError(fieldError);
                    ans = false;
                }
            }
        }

        return ans;
    }

    //  検索条件のチェック
    public boolean isValid(TodoQuery todoQuery, BindingResult result, Locale locale) {
        boolean ans = true;

        // 期限:開始の形式をチェック
        String date = todoQuery.getDeadlineFrom();
        if (!date.equals("")) {
            try {
                LocalDate.parse(date);
            } catch (DateTimeException e) {
                FieldError fieldError = new FieldError(
                        result.getObjectName(),
                        "deadlineFrom",
                        messageSource.getMessage("InvalidFormat.todoQuery.deadlineFrom", null, locale));
                result.addError(fieldError);
                ans = false;
            }
        }
        // 期限:終了の形式をチェック
        date = todoQuery.getDeadlineTo();
        if (!date.equals("")) {
            try {
                LocalDate.parse(date);
            } catch (DateTimeException e) {
                // parseできない場合
                FieldError fieldError = new FieldError(
                        result.getObjectName(),
                        "deadlineTo",
                        messageSource.getMessage("InvalidFormat.todoQuery.deadlineTo", null, locale));
                result.addError(fieldError);
                ans = false;
            }
        }
        return ans;
    }

    // 新規Taskのチェック
    public boolean isValid(TaskData taskData, BindingResult result, Locale locale) {
        boolean ans = true;

        // タスクの件名が半角スペースだけ or "" ならエラー
        if (Utils.isBlank(taskData.getTitle())) {
            FieldError fieldError = new FieldError(
                    result.getObjectName(),
                    "newTask.title",
                    messageSource.getMessage("NotBlank.taskData.title", null, locale));
            result.addError(fieldError);
            ans = false;

        } else {
            // タスクの件名が全角スペースだけで構成されていたらエラー
            if (Utils.isAllDoubleSpace(taskData.getTitle())) {
                FieldError fieldError = new FieldError(
                        result.getObjectName(),
                        "newTask.title",
                        messageSource.getMessage(
                                "DoubleSpace.todoData.title", null, locale));
                result.addError(fieldError);
                ans = false;
            }
        }

        // 期限が""ならチェックしない
        String deadline = taskData.getDeadline();
        if (deadline.equals("")) {
            return ans;
        }

        // 期限のyyyy-mm-dd形式チェック
        if (!Utils.isValidDateFormat(deadline)) {
            FieldError fieldError = new FieldError(
                    result.getObjectName(),
                    "newTask.deadline",
                    messageSource.getMessage(
                            "InvalidFormat.todoData.deadline", null, locale));
            result.addError(fieldError);
            ans = false;

        } else {
            // 過去日付ならエラー
            if (!Utils.isTodayOrFutureDate(deadline)) {
                FieldError fieldError = new FieldError(
                        result.getObjectName(),
                        "newTask.deadline",
                        messageSource.getMessage("Past.todoData.deadline", null, locale));
                result.addError(fieldError);
                ans = false;
            }
        }

        return ans;
    }

    //  自動生成されたメソッドによる検索 
    public List<Todo> doQuery(TodoQuery todoQuery) {
        List<Todo> todoList = null;
        if (todoQuery.getTitle().length() > 0) {
            // タイトルで検索
            todoList = todoRepository.findByTitleLike("%" + todoQuery.getTitle() + "%");

        } else if (todoQuery.getImportance() != null && todoQuery.getImportance() != -1) {
            // 重要度で検索
            todoList = todoRepository.findByImportance(todoQuery.getImportance());

        } else if (todoQuery.getUrgency() != null && todoQuery.getUrgency() != -1) {
            // 緊急度で検索
            todoList = todoRepository.findByUrgency(todoQuery.getUrgency());

        } else if (!todoQuery.getDeadlineFrom().equals("") &&
                todoQuery.getDeadlineTo().equals("")) {
            // 期限 開始～
            todoList = todoRepository
                    .findByDeadlineGreaterThanEqualOrderByDeadlineAsc(
                            Utils.str2date(todoQuery.getDeadlineFrom()));

        } else if (todoQuery.getDeadlineFrom().equals("") &&
                !todoQuery.getDeadlineTo().equals("")) {
            // 期限 ～終了
            todoList = todoRepository
                    .findByDeadlineLessThanEqualOrderByDeadlineAsc(
                            Utils.str2date(todoQuery.getDeadlineTo()));

        } else if (!todoQuery.getDeadlineFrom().equals("") &&
                !todoQuery.getDeadlineTo().equals("")) {
            // 期限 開始～終了
            todoList = todoRepository
                    .findByDeadlineBetweenOrderByDeadlineAsc(
                            Utils.str2date(todoQuery.getDeadlineFrom()),
                            Utils.str2date(todoQuery.getDeadlineTo()));

        } else if (todoQuery.getDone() != null && todoQuery.getDone().equals("Y")) {
            // 完了で検索
            todoList = todoRepository.findByDone("Y");

        } else {
            // 入力条件が無ければ全件検索
            todoList = todoRepository.findAll();
        }

        return todoList;
    }

    // Native Queryによる検索
    public Page<Todo> searchWithNativeQuery(TodoQuery todoQuery, Pageable pageable) {
        String title = todoQuery.getTitle().isEmpty()
                ? null
                : "%" + todoQuery.getTitle() + "%";
        Integer importance = todoQuery.getImportance() == -1
                ? null
                : todoQuery.getImportance();
        Integer urgency = todoQuery.getUrgency() == -1
                ? null
                : todoQuery.getUrgency();
        LocalDate deadlineFrom = todoQuery.getDeadlineFrom().isEmpty()
                ? null
                : Utils.str2date(todoQuery.getDeadlineFrom());
        LocalDate deadlineTo = todoQuery.getDeadlineTo().isEmpty()
                ? null
                : Utils.str2date(todoQuery.getDeadlineTo());
        String done = (todoQuery.getDone() == null || todoQuery.getDone().isEmpty())
                ? null
                : todoQuery.getDone();

        return todoRepository.searchByNativeQuery(
                title,
                importance,
                urgency,
                deadlineFrom,
                deadlineTo,
                done,
                pageable);
    }

}
