"""bmadnotion CLI - Command line interface for BMAD to Notion sync."""

from pathlib import Path

import click

from bmadnotion import __version__
from bmadnotion.config import ConfigNotFoundError, TokenNotFoundError, load_config
from bmadnotion.store import Store

# Import NotionClient from marknotion for use in commands
try:
    from marknotion import NotionClient
except ImportError:
    NotionClient = None  # type: ignore


def get_project_root() -> Path:
    """Get the project root (current working directory)."""
    return Path.cwd()


@click.group()
@click.version_option(version=__version__, prog_name="bmadnotion")
def cli():
    """Sync BMAD project artifacts to Notion.

    bmadnotion syncs your BMAD project's planning artifacts and sprint
    tracking to Notion, keeping your documentation and progress in sync.
    """
    pass


@cli.command()
@click.option("--project", "-p", help="Project name")
@click.option("--force", "-f", is_flag=True, help="Overwrite existing config")
def init(project: str | None, force: bool):
    """Initialize bmadnotion configuration.

    Creates a .bmadnotion.yaml configuration file in the current directory.
    """
    project_root = get_project_root()
    config_path = project_root / ".bmadnotion.yaml"

    # Check if config already exists
    if config_path.exists() and not force:
        click.echo(f"Configuration file already exists: {config_path}")
        click.echo("Use --force to overwrite.")
        return

    # Use project name from option or directory name
    if not project:
        project = project_root.name

    click.echo(f"Initializing bmadnotion for project: {project}")

    # Generate default configuration
    config_content = f'''# bmadnotion configuration
# Generated by: bmadnotion init

project: {project}

notion:
  # Environment variable containing your Notion API token
  token_env: NOTION_TOKEN
  # Your Notion workspace page ID (for reference)
  workspace_page_id: "your-workspace-page-id"

# Page Sync: Sync planning artifacts to Notion Pages
page_sync:
  enabled: true
  # Parent page ID where documents will be created
  parent_page_id: "your-parent-page-id"
  documents:
    - path: "prd.md"
      title: "PRD - {project}"
    - path: "architecture.md"
      title: "Architecture - {project}"
    - path: "ux-design-specification.md"
      title: "UX Design - {project}"

# Database Sync: Sync sprint status to Notion Databases
database_sync:
  enabled: true
  sprints:
    # Notion database ID for Epics/Sprints
    database_id: "your-sprints-database-id"
    status_mapping:
      backlog: "Not Started"
      in-progress: "In Progress"
      done: "Done"
  tasks:
    # Notion database ID for Stories/Tasks
    database_id: "your-tasks-database-id"
    status_mapping:
      backlog: "Backlog"
      ready-for-dev: "Ready"
      in-progress: "In Progress"
      review: "Review"
      done: "Done"
'''

    config_path.write_text(config_content)
    click.echo(f"Created {config_path}")
    click.echo("")
    click.echo("Next steps:")
    click.echo("  1. Set your NOTION_TOKEN environment variable")
    click.echo("  2. Update the page/database IDs in .bmadnotion.yaml")
    click.echo("  3. Run 'bmadnotion sync' to sync your project")


@cli.group(invoke_without_command=True)
@click.option("--force", "-f", is_flag=True, help="Force full sync, ignore cache")
@click.option("--dry-run", is_flag=True, help="Preview changes without syncing")
@click.pass_context
def sync(ctx, force: bool, dry_run: bool):
    """Sync artifacts to Notion.

    Without a subcommand, syncs all artifacts (both pages and database).
    """
    ctx.ensure_object(dict)
    ctx.obj["force"] = force
    ctx.obj["dry_run"] = dry_run

    if ctx.invoked_subcommand is None:
        # No subcommand given, sync all
        ctx.invoke(sync_pages, force=force, dry_run=dry_run)
        ctx.invoke(sync_db, force=force, dry_run=dry_run)


@sync.command("pages")
@click.option("--force", "-f", is_flag=True, help="Force full sync, ignore cache")
@click.option("--dry-run", is_flag=True, help="Preview changes without syncing")
def sync_pages(force: bool, dry_run: bool):
    """Sync planning artifacts to Notion Pages.

    Syncs documents like PRD, Architecture, and UX Design to Notion pages.
    """
    from bmadnotion.page_sync import PageSyncEngine

    project_root = get_project_root()

    # Load configuration
    try:
        config = load_config(project_root)
    except ConfigNotFoundError as e:
        click.echo(f"Error: {e}", err=True)
        raise SystemExit(1)

    # Check if page sync is enabled
    if not config.page_sync.enabled:
        click.echo("Page sync is disabled in configuration.")
        return

    # Get Notion token
    try:
        token = config.get_notion_token()
    except TokenNotFoundError as e:
        click.echo(f"Error: {e}", err=True)
        raise SystemExit(1)

    # Create Notion client
    if NotionClient is None:
        click.echo("Error: marknotion is not installed.", err=True)
        raise SystemExit(1)

    client = NotionClient(token=token)
    store = Store(project_root)
    engine = PageSyncEngine(client, store, config)

    # Perform sync
    mode = "[DRY RUN] " if dry_run else ""
    click.echo(f"{mode}Syncing pages...")

    result = engine.sync(force=force, dry_run=dry_run)

    # Display results
    if dry_run:
        click.echo(f"Would create: {result.created}")
        click.echo(f"Would update: {result.updated}")
        click.echo(f"Would skip: {result.skipped}")
    else:
        click.echo(f"Created: {result.created}")
        click.echo(f"Updated: {result.updated}")
        click.echo(f"Skipped: {result.skipped}")

    if result.failed > 0:
        click.echo(f"Failed: {result.failed}", err=True)
        for error in result.errors:
            click.echo(f"  - {error}", err=True)

    click.echo("Done.")


@sync.command("db")
@click.option("--force", "-f", is_flag=True, help="Force full sync, ignore cache")
@click.option("--dry-run", is_flag=True, help="Preview changes without syncing")
def sync_db(force: bool, dry_run: bool):
    """Sync sprint status to Notion Database.

    Syncs Epics and Stories from sprint-status.yaml to Notion databases.
    """
    from bmadnotion.db_sync import DbSyncEngine
    from bmadnotion.scanner import SprintStatusNotFoundError

    project_root = get_project_root()

    # Load configuration
    try:
        config = load_config(project_root)
    except ConfigNotFoundError as e:
        click.echo(f"Error: {e}", err=True)
        raise SystemExit(1)

    # Check if database sync is enabled
    if not config.database_sync.enabled:
        click.echo("Database sync is disabled in configuration.")
        return

    # Get Notion token
    try:
        token = config.get_notion_token()
    except TokenNotFoundError as e:
        click.echo(f"Error: {e}", err=True)
        raise SystemExit(1)

    # Create Notion client
    if NotionClient is None:
        click.echo("Error: marknotion is not installed.", err=True)
        raise SystemExit(1)

    client = NotionClient(token=token)
    store = Store(project_root)
    engine = DbSyncEngine(client, store, config)

    # Perform sync
    mode = "[DRY RUN] " if dry_run else ""
    click.echo(f"{mode}Syncing database...")

    try:
        result = engine.sync(force=force, dry_run=dry_run)
    except SprintStatusNotFoundError as e:
        click.echo(f"Error: {e}", err=True)
        raise SystemExit(1)

    # Display results
    click.echo("")
    click.echo("Epics (Sprints):")
    if dry_run:
        click.echo(f"  Would create: {result.epics_created}")
        click.echo(f"  Would update: {result.epics_updated}")
        click.echo(f"  Would skip: {result.epics_skipped}")
    else:
        click.echo(f"  Created: {result.epics_created}")
        click.echo(f"  Updated: {result.epics_updated}")
        click.echo(f"  Skipped: {result.epics_skipped}")

    click.echo("")
    click.echo("Stories (Tasks):")
    if dry_run:
        click.echo(f"  Would create: {result.stories_created}")
        click.echo(f"  Would update: {result.stories_updated}")
        click.echo(f"  Would skip: {result.stories_skipped}")
    else:
        click.echo(f"  Created: {result.stories_created}")
        click.echo(f"  Updated: {result.stories_updated}")
        click.echo(f"  Skipped: {result.stories_skipped}")

    if result.epics_failed > 0 or result.stories_failed > 0:
        click.echo("")
        click.echo(f"Failed: {result.epics_failed + result.stories_failed}", err=True)
        for error in result.errors:
            click.echo(f"  - {error}", err=True)

    click.echo("")
    click.echo("Done.")


@cli.command()
def status():
    """Show sync status.

    Displays the current sync state, showing what's changed locally
    and what needs to be synced to Notion.
    """
    from bmadnotion.scanner import BMADScanner, SprintStatusNotFoundError

    project_root = get_project_root()

    # Load configuration
    try:
        config = load_config(project_root)
    except ConfigNotFoundError as e:
        click.echo(f"Error: {e}", err=True)
        raise SystemExit(1)

    store = Store(project_root)
    scanner = BMADScanner(config)

    click.echo(f"Project: {config.project}")
    click.echo("")

    # Page sync status
    if config.page_sync.enabled:
        click.echo("=== Page Sync (Planning Artifacts) ===")
        documents = scanner.scan_documents()

        synced = 0
        pending = 0
        changed = 0

        for doc in documents:
            state = store.get_page_state(doc.path.name)
            if state is None:
                pending += 1
                click.echo(f"  [NEW] {doc.path.name}")
            elif state.content_hash != doc.content_hash:
                changed += 1
                click.echo(f"  [CHANGED] {doc.path.name}")
            else:
                synced += 1

        if synced > 0 and pending == 0 and changed == 0:
            click.echo(f"  ✓ All {synced} documents synced")
        else:
            click.echo(f"\n  Synced: {synced}, Pending: {pending}, Changed: {changed}")
        click.echo("")
    else:
        click.echo("=== Page Sync: Disabled ===")
        click.echo("")

    # Database sync status
    if config.database_sync.enabled:
        click.echo("=== Database Sync (Sprint Status) ===")

        try:
            epics, stories = scanner.scan_sprint_status()

            epics_synced = 0
            epics_pending = 0
            epics_changed = 0

            for epic in epics:
                state = store.get_db_state(epic.key)
                if state is None:
                    epics_pending += 1
                elif epic.mtime and state.last_synced_mtime != epic.mtime:
                    epics_changed += 1
                else:
                    epics_synced += 1

            stories_synced = 0
            stories_pending = 0
            stories_changed = 0

            for story in stories:
                state = store.get_db_state(story.key)
                if state is None:
                    stories_pending += 1
                elif story.content_hash and state.content_hash != story.content_hash:
                    stories_changed += 1
                elif story.mtime and state.last_synced_mtime != story.mtime:
                    stories_changed += 1
                else:
                    stories_synced += 1

            click.echo(
                f"  Epics:   Synced: {epics_synced}, "
                f"Pending: {epics_pending}, Changed: {epics_changed}"
            )
            click.echo(
                f"  Stories: Synced: {stories_synced}, "
                f"Pending: {stories_pending}, Changed: {stories_changed}"
            )

            all_synced = (
                epics_pending == 0
                and epics_changed == 0
                and stories_pending == 0
                and stories_changed == 0
            )
            if all_synced:
                click.echo("\n  ✓ All items up to date")

        except SprintStatusNotFoundError:
            click.echo("  No sprint-status.yaml found")

        click.echo("")
    else:
        click.echo("=== Database Sync: Disabled ===")
        click.echo("")


@cli.group()
def config():
    """Manage configuration."""
    pass


@config.command("show")
def config_show():
    """Show current configuration."""

    project_root = get_project_root()

    try:
        config = load_config(project_root)
    except ConfigNotFoundError as e:
        click.echo(f"Error: {e}", err=True)
        raise SystemExit(1)

    click.echo(f"Project: {config.project}")
    click.echo(f"Config file: {project_root / '.bmadnotion.yaml'}")
    click.echo("")

    click.echo("Notion:")
    click.echo(f"  Token env: {config.notion.token_env}")
    click.echo(f"  Workspace page: {config.notion.workspace_page_id}")
    click.echo("")

    click.echo("Page Sync:")
    click.echo(f"  Enabled: {config.page_sync.enabled}")
    if config.page_sync.enabled:
        click.echo(f"  Parent page: {config.page_sync.parent_page_id}")
        click.echo(f"  Documents: {len(config.page_sync.documents)}")
        for doc in config.page_sync.documents:
            click.echo(f"    - {doc.path}: {doc.title}")
    click.echo("")

    click.echo("Database Sync:")
    click.echo(f"  Enabled: {config.database_sync.enabled}")
    if config.database_sync.enabled:
        click.echo(f"  Sprints DB: {config.database_sync.sprints.database_id}")
        click.echo(f"  Tasks DB: {config.database_sync.tasks.database_id}")


if __name__ == "__main__":
    cli()
