import argparse
import json
import os
import shutil
from .mbox import sync_mailing_list
from .github import download_github_issues, process_github_issues
from .meetings import process_meetings
from .charter import process_charter
from .drafts import process_documents
from .transcripts import process_transcripts
from .utils import (
    Verbosity,
    LogLevel,
    log,
    get_config_dir,
    get_wg_title,
    DEFAULT_MONTHS,
    get_wg_file_cache_dir,
    copy_if_updated,
    get_cache_dir,
)
from .notebooklm import (
    get_credentials,
    create_notebook,
    upload_source,
)


def load_config_args(wg_name: str) -> dict:
    """Load persisted arguments for a Working Group."""
    config_file = os.path.join(get_config_dir(), wg_name, "config.json")
    if os.path.exists(config_file):
        try:
            with open(config_file, "r", encoding="utf-8") as file_handle:
                return dict(json.load(file_handle))
        except (json.JSONDecodeError, OSError):
            pass
    return {}


def save_config_args(wg_name: str, args: dict) -> None:
    """Save arguments for a Working Group."""
    wg_config_dir = os.path.join(get_config_dir(), wg_name)
    os.makedirs(wg_config_dir, exist_ok=True)
    config_file = os.path.join(wg_config_dir, "config.json")
    try:
        with open(config_file, "w", encoding="utf-8") as file_handle:
            json.dump(args, file_handle, indent=2)
    except OSError as err:
        log(f"Error saving config: {err}", level=LogLevel.ERROR)


def merge_config_args(args: argparse.Namespace) -> None:
    """Merge and persist configuration arguments."""
    # Handle --clear-config
    if args.clear_config:
        wg_config_dir = os.path.join(get_config_dir(), args.wg)
        if os.path.exists(wg_config_dir):
            if not getattr(args, "quiet", False):
                print(f"Clearing configuration for {args.wg}...")
            shutil.rmtree(wg_config_dir)

    # Load and merge config
    persisted = load_config_args(args.wg)

    # Persistence logic:
    # 1. Scalars: CLI overrides persisted. If not in CLI, use persisted.
    # 2. Lists: CLI extends persisted.

    persistable_scalars = [
        "github",
        "destination",
        "create",
        "credentials_file",
        "token_file",
        "months",
    ]
    persistable_lists = ["github_label", "exclude_github_label"]

    for key in persistable_scalars:
        val = getattr(args, key)
        # Check if it's the default value for some arguments
        is_default = False
        val = getattr(args, key)
        # Check if it's the default value for some arguments
        is_default = False
        if key == "credentials_file" and val == os.path.join(
            get_config_dir(), "client_secrets.json"
        ):
            is_default = True
        elif key == "token_file" and val == os.path.join(
            get_config_dir(), "token.json"
        ):
            is_default = True
        elif key == "months" and val == DEFAULT_MONTHS:
            is_default = True

        if (val is None or is_default) and key in persisted:
            setattr(args, key, persisted[key])
        elif val is not None and not is_default:
            persisted[key] = val

    for key in persistable_lists:
        cli_vals = getattr(args, key) or []
        persisted_vals = persisted.get(key, [])
        combined = list(set(persisted_vals + cli_vals))
        setattr(args, key, combined if combined else None)
        if combined:
            persisted[key] = combined

    # Save updated config
    save_config_args(args.wg, persisted)


def export_to_notebooklm(
    args: argparse.Namespace, cache_dir: str, verbosity: Verbosity
) -> None:
    """Upload cached documents to a new NotebookLM notebook."""
    gcp_project = args.create
    print("-" * 40)
    print("Exporting to NotebookLM...")

    creds = get_credentials(args.credentials_file, args.token_file, verbose=verbosity)
    if not creds:
        log("Authentication failed.", verbosity, level=LogLevel.ERROR)
        return

    wg_title = get_wg_title(args.wg)
    notebook_title = f"IETF {wg_title} Working Group"
    notebook_id = create_notebook(gcp_project, notebook_title, creds, verbose=verbosity)

    if not notebook_id:
        log("Failed to create notebook.", verbosity, level=LogLevel.ERROR)
        return

    success_count = 0
    # When creating a new notebook, upload all relevant text files from the CACHE.
    all_cache_files = [
        os.path.join(cache_dir, f)
        for f in os.listdir(cache_dir)
        if f.endswith((".txt", ".md"))
    ]
    for file_path in sorted(list(set(all_cache_files))):
        if upload_source(
            gcp_project,
            notebook_id,
            file_path,
            creds,
            verbose=verbosity,
        ):
            success_count += 1

    if success_count > 0:
        print(
            f"Successfully uploaded {success_count} files "
            f"to notebook '{notebook_title}'."
        )
    else:
        log(
            "No files were uploaded to the notebook.",
            verbosity,
            level=LogLevel.ERROR,
        )


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Automate creation of NotebookLM-ready documents for an IETF Working Group."
    )
    parser.add_argument("wg", help="IETF Working Group short name (e.g., 'httpbis')")
    parser.add_argument(
        "--github", help="GitHub owner/repo (e.g., 'ietf-wg-httpbis/wg-materials')"
    )
    parser.add_argument(
        "--months",
        type=int,
        default=DEFAULT_MONTHS,
        help=f"Number of months of materials and emails to fetch (default: {DEFAULT_MONTHS})",
    )
    parser.add_argument(
        "--github-label",
        action="append",
        help="Include only GitHub issues with this label (can be specified multiple times)",
    )
    parser.add_argument(
        "--exclude-github-label",
        action="append",
        help="Exclude GitHub issues with this label (can be specified multiple times)",
    )
    parser.add_argument(
        "--destination",
        help="Destination folder for exported documents (required on first run)",
    )
    parser.add_argument("--quiet", "-q", action="store_true", help="Only output errors")
    parser.add_argument(
        "--verbose", "-v", action="store_true", help="Detailed progress reporting"
    )

    parser.add_argument(
        "--create",
        metavar="GCP_PROJECT_ID",
        help="Upload the generated files to a new notebook in NotebookLM",
    )
    parser.add_argument(
        "--clear-config",
        action="store_true",
        help="Clear the persisted configuration for this Working Group",
    )
    parser.add_argument(
        "--credentials-file",
        default=os.path.join(get_config_dir(), "client_secrets.json"),
        help="Path to the Google Cloud OAuth client secrets file",
    )
    parser.add_argument(
        "--token-file",
        default=os.path.join(get_config_dir(), "token.json"),
        help="Path to the Google Cloud OAuth token file",
    )
    parser.add_argument(
        "--clear-cache",
        action="store_true",
        help="Clear the local file cache for this Working Group and start fresh.",
    )

    args = parser.parse_args()

    merge_config_args(args)

    if not args.destination:
        print("Error: --destination is required (either on command line or from config).")
        print(f"Usage: ietf-notebook {args.wg} --destination ./my-docs")
        return

    # 1. Clear destination folder to ensure it only contains this run's updates
    if os.path.exists(args.destination):
        shutil.rmtree(args.destination)
    os.makedirs(args.destination)

    # 1. Handle --clear-cache
    wg_cache_dir = os.path.join(get_cache_dir(), args.wg)
    cache_dir = get_wg_file_cache_dir(args.wg)
    if args.clear_cache:
        log(f"Clearing cache for {args.wg}...", Verbosity.STATUS)
        if os.path.exists(wg_cache_dir):
            shutil.rmtree(wg_cache_dir)
        os.makedirs(cache_dir, exist_ok=True)

    verbosity = Verbosity.STATUS
    if args.quiet:
        verbosity = Verbosity.QUIET
    elif args.verbose:
        verbosity = Verbosity.VERBOSE

    if verbosity != Verbosity.QUIET:
        print(f"Processing WG: {args.wg}")
        print(f"Destination: {args.destination}")
        if args.clear_cache:
            print("Clear cache: Re-downloading all materials.")
        else:
            print("Default mode: Using local cache for existing materials.")
        print("-" * 40)

    # We will collect all files generated by the processors in the cache.
    # We then mirror them to the destination.
    generated_cache_files = []

    # 1. Charter
    charter_file = os.path.join(cache_dir, f"{args.wg}-charter.txt")
    generated_cache_files.extend(
        process_charter(args.wg, charter_file, verbose=verbosity)
    )

    # 2. Meetings
    generated_cache_files.extend(
        process_meetings(
            args.wg,
            cache_dir,
            verbose=verbosity,
            months=args.months,
        )
    )

    # 3. Mailing List
    generated_cache_files.extend(
        sync_mailing_list(
            args.wg, cache_dir, months=args.months, verbose=verbosity
        )
    )

    # 4. Transcripts
    generated_cache_files.extend(
        process_transcripts(
            args.wg,
            cache_dir,
            verbose=verbosity,
            months=args.months,
        )
    )

    # 5. Documents (Drafts & RFCs)
    generated_cache_files.extend(
        process_documents(
            args.wg, cache_dir, verbose=verbosity
        )
    )

    # 6. GitHub Issues
    if args.github:
        gh_json = os.path.join(cache_dir, f"{args.wg}-github-issues.json")
        gh_txt = os.path.join(cache_dir, f"{args.wg}-github-issues.txt")
        if download_github_issues(args.github, gh_json, verbose=verbosity):
            generated_cache_files.append(gh_json)
            generated_cache_files.extend(
                process_github_issues(
                    gh_json,
                    gh_txt,
                    include_labels=args.github_label,
                    exclude_labels=args.exclude_github_label,
                    verbose=verbosity,
                )
            )

    # 7. Mirror to destination
    updated_files = []
    # Filter out internal JSON/binary files from mirroring to destination if appropriate
    # but for now we mirror all returned generated files.
    for src in sorted(list(set(generated_cache_files))):
        if not os.path.exists(src):
            continue
        if src.endswith(".json"): # Don't mirror internal JSON
            continue
        filename = os.path.basename(src)
        dst = os.path.join(args.destination, filename)
        if copy_if_updated(src, dst):
            updated_files.append(dst)

    if args.create:
        export_to_notebooklm(args, cache_dir, verbosity)

    if verbosity != Verbosity.QUIET:
        print("-" * 40)
        if updated_files:
            print(f"Updated {len(updated_files)} files in {args.destination}.")
        else:
            print("No files updated in destination.")
        print("All tasks completed.")


if __name__ == "__main__":
    main()
