# SPDX-FileCopyrightText: 2022 Chris Heywood
#
# SPDX-License-Identifier: GPL-3.0-or-later

from datetime import datetime, timedelta
import os
import shutil
import unittest
import warnings

from iotas.category import Category, CategorySpecialPurpose
from iotas.category_manager import CategoryManager
from iotas.database import Database
from iotas.note import Note
from iotas.note_database import NoteDatabase
import iotas.note_manager
from iotas.note_manager import NoteManager

warnings.filterwarnings("ignore", "version")

# Note: very focused testing here so far purely for issues with the filters for the note list
# sections. Coverage very low and even the filter testing is narrow.


class Test(unittest.TestCase):

    note_fake_id = 1
    now: datetime

    def test_filter_cutoff_duplicates(self) -> None:
        # Typical thresholds
        self.__reset(datetime(2025, 9, 19, 14, 11, 0))
        notes = []
        notes.append(self.__create_dummy_note(0))
        notes.append(self.__create_dummy_note(1))
        notes.append(self.__create_dummy_note(2))
        notes.append(self.__create_dummy_note(4))
        notes.append(self.__create_dummy_note(5))
        notes.append(self.__create_dummy_note(18))
        notes.append(self.__create_dummy_note(19))
        notes.append(self.__create_dummy_note(49))
        notes.append(self.__create_dummy_note(50))
        self.__add_and_invalidate(notes)
        self.assertEqual(self.__get_model_totals(), [1, 1, 2, 2, 2, 1])

        # Fishing over a year
        # start = datetime(2025, 9, 15, 14, 11, 0)
        # for ago in range(0, 366):
        #     dt = start - timedelta(days=ago)
        #     self.__reset(dt)
        #     notes = []
        #     notes.append(self.__create_dummy_note(0))
        #     notes.append(self.__create_dummy_note(1))
        #     notes.append(self.__create_dummy_note(2))
        #     notes.append(self.__create_dummy_note(4))
        #     notes.append(self.__create_dummy_note(5))
        #     notes.append(self.__create_dummy_note(18))
        #     notes.append(self.__create_dummy_note(19))
        #     notes.append(self.__create_dummy_note(49))
        #     notes.append(self.__create_dummy_note(50))
        #     notes.append(self.__create_dummy_note(80))
        #     self.__add_and_invalidate(notes)
        #     self.assertEqual(self.__get_models_sum(), 10)

        # First day of week is first day of month
        self.__reset(datetime(2025, 9, 4, 14, 11, 0))
        notes = []
        notes.append(self.__create_dummy_note(0))
        notes.append(self.__create_dummy_note(1))
        notes.append(self.__create_dummy_note(2))
        notes.append(self.__create_dummy_note(3))
        self.__add_and_invalidate(notes)
        self.assertEqual(self.__get_model_totals(), [1, 1, 2, 0, 0, 0])

        # Yesterday is first day of month
        self.__reset(datetime(2025, 8, 2, 14, 11, 0))
        notes = []
        notes.append(self.__create_dummy_note(1))
        self.__add_and_invalidate(notes)
        self.assertEqual(self.__get_model_totals(), [0, 1, 0, 0, 0, 0])

        # Yesterday is first day of month and first day of month
        self.__reset(datetime(2024, 7, 2, 14, 11, 0))
        notes = []
        notes.append(self.__create_dummy_note(0))
        notes.append(self.__create_dummy_note(1))
        notes.append(self.__create_dummy_note(2))
        self.__add_and_invalidate(notes)
        self.assertEqual(self.__get_model_totals(), [1, 1, 0, 0, 1, 0])

        # Yesterday is last week
        self.__reset(datetime(2025, 9, 15, 14, 11, 0))
        notes = []
        notes.append(self.__create_dummy_note(1))
        self.__add_and_invalidate(notes)
        self.assertEqual(self.__get_model_totals(), [0, 1, 0, 0, 0, 0])

        # Yesterday is last month
        self.__reset(datetime(2025, 8, 1, 14, 11, 0))
        notes = []
        notes.append(self.__create_dummy_note(1))
        self.__add_and_invalidate(notes)
        self.assertEqual(self.__get_model_totals(), [0, 1, 0, 0, 0, 0])

        # Yesterday is last week and last month
        self.__reset(datetime(2025, 9, 1, 14, 11, 0))
        notes = []
        notes.append(self.__create_dummy_note(1))
        self.__add_and_invalidate(notes)
        self.assertEqual(self.__get_model_totals(), [0, 1, 0, 0, 0, 0])

        self.__clean_output_dir()

    def __create_dummy_note(self, days_prior: int) -> Note:
        note = Note(new_note=True)
        note.title = note.content = f"{days_prior} days prior"
        note.last_modified = self.__create_timestamp(days_prior, self.now)
        note.id = self.note_fake_id
        self.note_fake_id += 1
        return note

    def __create_timestamp(self, days_prior: int, now: datetime) -> float:
        val = now - timedelta(days=days_prior)
        # logging.warning(f"{days_prior} days before {now} is {val}")
        return int(val.timestamp())

    def __reset(self, now: datetime) -> NoteManager:
        self.now = now
        self.__prepare_output_dir()
        storage_dir = self.__get_output_dir()
        self.db = NoteDatabase(Database(storage_dir))
        self.category_manager = CategoryManager(self.db)
        self.note_manager = NoteManager(self.db, self.category_manager)
        self.note_manager.initiate_older_notes_model()
        self.note_fake_id = 1
        iotas.note_manager.get_now = self.__get_test_now
        return self.note_manager

    def __prepare_output_dir(self) -> str:
        out_path = self.__get_output_dir()
        if os.path.exists(out_path):
            shutil.rmtree(out_path)
        os.makedirs(out_path)
        return out_path

    def __clean_output_dir(self) -> None:
        out_path = self.__get_output_dir()
        if os.path.exists(out_path):
            shutil.rmtree(out_path)

    def __get_output_dir(self) -> str:
        file_dir = os.path.dirname(__file__)
        return os.path.join(file_dir, os.pardir, "testing-tmp")

    def __get_model_totals(self) -> list[int]:
        # logging.warning(f"Today {self.note_manager.today_model.get_n_items()}")
        # logging.warning(f"Yesterday {self.note_manager.yesterday_model.get_n_items()}")
        # logging.warning(f"Week {self.note_manager.week_model.get_n_items()}")
        # logging.warning(f"Month {self.note_manager.month_model.get_n_items()}")
        # logging.warning(f"Last month {self.note_manager.last_month_model.get_n_items()}")
        # logging.warning(f"Older {self.note_manager.older_notes_model.get_n_items()}")
        models = [
            self.note_manager.today_model,
            self.note_manager.yesterday_model,
            self.note_manager.week_model,
            self.note_manager.month_model,
            self.note_manager.last_month_model,
            self.note_manager.older_notes_model,
        ]
        totals = []
        for model in models:
            totals.append(model.get_n_items())
        return totals

    def __get_models_sum(self) -> int:
        return sum(self.__get_model_totals())

    def __update_filters(self) -> None:
        all_category = Category("", 0)
        all_category.special_purpose = CategorySpecialPurpose.ALL
        self.note_manager.update_filters(all_category, True, False)

    def __get_test_now(self) -> datetime:
        return self.now

    def __add_and_invalidate(self, notes: list[Note]) -> None:
        self.note_manager.add_notes_to_model(notes)
        self.__update_filters()
