from datetime import datetime, timedelta
from pathlib import Path

import pytest

from ..config.settings import AutoTagRule, Settings
from ..models import EntryListFilter
from ..repositories.time_entry_repo_yaml import TimeEntryRepositoryYaml
from ..services import EditorService, TimeTrackingService, YAMLEditorService


class DummyEditorService(EditorService):
    def edit_entry(self, entry):
        entry.comment = "edited by dummy editor"
        return entry


def create_test_settings(tmp_path: Path) -> Settings:
    """Create test settings with a specific configuration"""
    settings = Settings(data_filename=str(tmp_path / "test.yaml"), locale="en_US")
    settings.auto_tag_rules = [
        AutoTagRule(pattern="^abc", match_type="regex", tags=["learning"]),
        AutoTagRule(pattern="^PROJ-\\d+", match_type="regex", tags=["work", "billable"]),
        AutoTagRule(pattern="(feature|bugfix)/", match_type="regex", tags=["development"]),
        AutoTagRule(pattern="-urgent$", match_type="regex", tags=["priority"]),
    ]
    return settings


def test_initialization(tmp_path):
    settings = create_test_settings(tmp_path)
    tts = TimeTrackingService(settings=settings)
    assert tts.settings == settings
    assert tts.repository.filename == tts.settings.data_filename
    assert isinstance(tts.editor, YAMLEditorService)
    tts = TimeTrackingService(settings=settings, editor=DummyEditorService("nothing"))
    assert isinstance(tts.editor, DummyEditorService)


def test_basic_time_tracking(tmp_path):
    filename = tmp_path / "test.yaml"
    settings = create_test_settings(tmp_path)
    tts = TimeTrackingService(repository=TimeEntryRepositoryYaml(filename), settings=settings)
    assert tts.list_entries() == []
    a = tts.start_tracking("test-project")
    assert a.end_time is None
    assert tts.get_active_entry() == a
    b = tts.stop_tracking()
    assert b.start_time == a.start_time
    assert b.end_time is not None
    c = tts.stop_tracking()
    assert c is None

    entries = tts.list_entries()
    assert len(entries) == 1
    assert entries[0] == b


def test_auto_tagging(tmp_path):
    filename = tmp_path / "test.yaml"
    settings = create_test_settings(tmp_path)
    tts = TimeTrackingService(repository=TimeEntryRepositoryYaml(filename), settings=settings)

    # Test regex matching with '^abc' pattern
    entry1 = tts.start_tracking("abc-learning-task")
    assert "learning" in entry1.tags
    tts.stop_tracking()

    # Test regex matching with '^PROJ-\d+' pattern
    entry2 = tts.start_tracking("PROJ-123")
    assert "work" in entry2.tags
    assert "billable" in entry2.tags
    tts.stop_tracking()

    # Test regex matching with '(feature|bugfix)/' pattern
    entry3 = tts.start_tracking("feature/new-ui")
    assert "development" in entry3.tags
    tts.stop_tracking()

    entry4 = tts.start_tracking("bugfix/issue-123")
    assert "development" in entry4.tags
    tts.stop_tracking()

    # Test regex matching with '-urgent$' pattern
    entry5 = tts.start_tracking("task-urgent")
    assert "priority" in entry5.tags
    tts.stop_tracking()

    # Test no auto-tagging for non-matching project
    entry6 = tts.start_tracking("regular-task")
    assert len(entry6.tags) == 0
    tts.stop_tracking()

    # Test merging auto-tags with user-provided tags
    entry7 = tts.start_tracking("abc-task", tags={"custom-tag"})
    assert "learning" in entry7.tags
    assert "custom-tag" in entry7.tags
    tts.stop_tracking()


def test_start_stop(tmp_path):
    filename = tmp_path / "test.yaml"
    settings = create_test_settings(tmp_path)
    tts = TimeTrackingService(repository=TimeEntryRepositoryYaml(filename), settings=settings)

    d1 = tts.start_tracking("test-project")
    assert d1.end_time is None
    d2 = tts.start_tracking("test-project-2")
    assert d2.end_time is None
    d1 = tts.get_entry(d1.id)
    assert d1.end_time is not None


def test_filtered_list(tmp_path):
    filename = tmp_path / "test.yaml"
    settings = create_test_settings(tmp_path)
    tts = TimeTrackingService(repository=TimeEntryRepositoryYaml(filename), settings=settings)

    # Create entries with different projects and tags
    d1 = tts.start_tracking("test-project", tags={"tag1", "tag2"})
    tts.stop_tracking()
    d2 = tts.start_tracking("test-project-2", tags={"tag2", "tag3"})
    tts.stop_tracking()
    d3 = tts.start_tracking("test-project-3", tags={"tag1", "tag3"})
    tts.stop_tracking()
    assert all(entry is not None for entry in [d1, d2, d3])

    # Test no filter
    l1 = tts.list_entries(filter=None)
    assert len(l1) == 3

    # Test project filter
    filter_by_projects = EntryListFilter(projects={"test-project", "test-project-2"})
    l2 = tts.list_entries(filter=filter_by_projects)
    assert len(l2) == 2
    assert all(e.project in {"test-project", "test-project-2"} for e in l2)

    # Test tag filter
    filter_by_tags = EntryListFilter(tags={"tag1"})
    l3 = tts.list_entries(filter=filter_by_tags)
    assert len(l3) == 2
    assert all("tag1" in e.tags for e in l3)

    # Test date filter
    now = datetime.now()
    yesterday = now - timedelta(days=1)
    filter_by_date = EntryListFilter(start_date=yesterday.date())
    l5 = tts.list_entries(filter=filter_by_date)
    assert len(l5) == 3

    # Test combined filters
    combined_filter = EntryListFilter(projects={"test-project"}, tags={"tag1"}, start_date=yesterday.date())
    l6 = tts.list_entries(filter=combined_filter)
    assert len(l6) == 1
    assert l6[0].project == "test-project"
    assert "tag1" in l6[0].tags

    # Test time period filter
    period_filter = EntryListFilter(time_period="today")
    l7 = tts.list_entries(filter=period_filter)
    assert len(l7) == 3
    assert all(e.start_time.date() == now.date() for e in l7)


def test_invalid_entry_fetch(tmp_path):
    filename = tmp_path / "test.yaml"
    settings = create_test_settings(tmp_path)
    tts = TimeTrackingService(repository=TimeEntryRepositoryYaml(filename), settings=settings)

    d1 = tts.start_tracking("test-project")
    assert d1.end_time is None
    tts.stop_tracking()
    d1 = tts.get_entry(d1.id)
    assert d1.end_time is not None

    with pytest.raises(KeyError):
        _ = tts.get_entry("invalid value here!")


def test_delete_entry(tmp_path):
    filename = tmp_path / "test.yaml"
    settings = create_test_settings(tmp_path)
    tts = TimeTrackingService(repository=TimeEntryRepositoryYaml(filename), settings=settings)

    d1 = tts.start_tracking("test-project")
    assert d1.end_time is None
    tts.stop_tracking()
    d1 = tts.get_entry(d1.id)
    assert d1.end_time is not None

    tts.delete_entry(d1.id)

    with pytest.raises(KeyError):
        _ = tts.get_entry(d1.id)


def test_configuration_loading(tmp_path):
    """Test that configuration is properly loaded and applied"""
    # Create a config file in the test directory
    config_file = tmp_path / ".sigye" / "config.yaml"
    config_file.parent.mkdir(parents=True, exist_ok=True)
    config_content = f"""
locale: ko_KR
data_filename: {str(tmp_path / "test.yaml")}
auto_tag_rules:
  - pattern: "^test-"
    match_type: "regex"
    tags: ["testing"]
"""
    config_file.write_text(config_content)

    # Create settings with the test directory as home
    settings = Settings.load_from_file(config_file)

    assert settings.locale == "ko_KR"  # Verify locale override

    # Create service and test auto-tagging
    tts = TimeTrackingService(repository=TimeEntryRepositoryYaml(settings.data_filename), settings=settings)

    entry = tts.start_tracking("test-project")
    assert "testing" in entry.tags


def test_edit_command(tmp_path):
    settings = create_test_settings(tmp_path)
    tts = TimeTrackingService(settings=settings, editor=DummyEditorService("nothing"))

    d1 = tts.start_tracking("test-project")
    assert d1.end_time is None
    d1 = tts.edit_entry(d1.id)
    d1 = tts.get_entry(d1.id)
    assert d1.comment == "edited by dummy editor"
