import argparse
import sys
import os
import json
import shutil
from getpass import getpass

import jwt
import requests

from .config import save_config, load_config, get_device_id
from .mcp_client import MCPClient
from .repo_utils import detect_repo_root, zip_repo
from .sync_manager import SyncManager
import socket


def handle_login(server_url: str = None):
    """
    Handles user authentication with the MCP server.
    """
    config = load_config()
    existing_token = config.get("access_token")
    if existing_token:
        try:
            decoded = jwt.decode(existing_token, options={"verify_signature": False})
            existing_email = decoded.get("email", "unknown")
            print(f"ℹ Currently logged in as: {existing_email}")
            choice = input("Switch account? (y/N): ").strip().lower()
            if choice not in ['y', 'yes']:
                print("Login cancelled.")
                print("Please enter your credentials to log in.")
                return
        except:
            pass

    email = input("Email: ").strip()
    license_key = input("License key: ").strip()
    
    # Idempotent check: Are we already logged in as this user?
    if existing_token:
        try:
            decoded = jwt.decode(existing_token, options={"verify_signature": False})
            if decoded.get("email") == email:
                print(f"✔ Already logged in as {email}. Nothing changed.")
                return
        except:
            pass

    device_id = get_device_id()

    device_name = socket.gethostname()

    client = MCPClient()
    if server_url:
        client.server_url = server_url

    try:
        result = client.call("login", {
            "email": email,
            "license_key": license_key,
            "device_id": device_id,
            "device_name": device_name
        })
        
        if result.get("status") == "success":
            token = result.get("access_token")
            if not token:
                print("✖ Login failed: No access token returned. Please check your credentials.")
                sys.exit(1)

            # LAZY CONFIG: Only save if login succeeded
            save_config({
                "access_token": token,
                "server_url": client.server_url,
                "device_id": device_id,
                "license_key": license_key
            })

            print(f"✔ {result.get('message')}")
            print("\n🚀 Next Step: Run 'codedthemes init' to initialize your repository and sync it with the cloud.")
        else:
            print(f"✖ {result.get('message', 'Login failed')}")
            sys.exit(1)
    except Exception as e:
        err_msg = str(e)
        if "timed out" in err_msg.lower():
            print(f"✖ Login failed: License server connection timed out. Please try again.")
        else:
            print(f"✖ Login failed: {err_msg}")
        sys.exit(1)


def handle_logout():
    """
    Clears local session and notifies server to de-authenticate this device.
    """
    try:
        config = load_config()
        token = config.get("access_token")
        license_key = config.get("license_key")
        
        if not token:
            print("ℹ Not logged in.")
            return

        device_id = get_device_id()
        client = MCPClient()
        
        print("Logging out...")
        if license_key:
            try:
                client.call("logout", {
                    "license_key": license_key,
                    "device_id": device_id
                })
            except Exception as e:
                # Silently fail if server logout fails, we still want to clear local state
                pass
        
        # Local cleanup: Remove config.json but KEEP device.json
        from .config import CONFIG_FILE
        if CONFIG_FILE.exists():
            CONFIG_FILE.unlink()
            
        print("✔ Logged out successfully.")
    except Exception as e:
        print(f"✖ Logout failed: {e}")


def handle_init():

    """
    Initializes the local repository and syncs it with the cloud.
    """
    try:
        repo_root = detect_repo_root()
        print(f"🔍 Found repository at {repo_root}")
        
        client = MCPClient()
        if not client.token:
            print("✖ Not logged in. Please run 'codedthemes login' first.")
            sys.exit(1)

        user_email = "unknown_user"
        try:
            decoded = jwt.decode(client.token, options={"verify_signature": False})
            user_email = decoded.get("email", "unknown_user")
        except:
            pass

        repo_abs_path = os.path.abspath(repo_root)
        repo_key = repo_abs_path.lower().replace(os.sep, "/")
        print("📦 Zipping and uploading repository (this may take a moment)...")
        upload_result = client.upload_workspace(repo_abs_path, user_email)
        workspace_id = upload_result.get("workspace_id")
        
        if not workspace_id:
            print("✖ Upload failed: No workspace ID returned.")
            sys.exit(1)

        config = load_config()
        last_workspaces = config.get("workspaces", {})
        last_workspaces[repo_key] = workspace_id
        config["workspaces"] = last_workspaces
        save_config(config)

        sync_manager = SyncManager()
        sync_manager.update_sync_state(repo_abs_path, workspace_id, user_email)

        print(f"✔ Workspace initialized successfully.")
        print(f"✔ Workspace ID: {workspace_id}")
        print("\n" + "="*60)
        print("Your repository is now synced to the cloud!")
        print("="*60)

        print("\n📌 Next Steps — Set up your IDE:\n")

        print("Choose your editor and add the MCP server:\n")

        # ---------------- ANTIGRAVITY ----------------
        print("🔹 Antigravity")
        print("   MCP Servers → Manage → Config\n")

        print('   {')
        print('     "mcpServers": {')
        print('       "code-theme-mcp": {')
        print('         "type": "sse",')
        print('         "serverURL": "https://mcp.codedthemes.com/api/mcp",')
        print(f'         "env": {{ "CODEDTHEMES_TOKEN": "{client.token}" }}')
        print('       }')
        print('     }')
        print('   }\n')

        # ---------------- VS CODE ----------------
        print("🔹 VS Code")
        print("   Ctrl+Shift+P → MCP: Add MCP Server → http\n")

        print('   {')
        print('     "servers": {')
        print('       "code-theme-mcp": {')
        print('         "url": "https://mcp.codedthemes.com/api/mcp",')
        print('         "type": "http",')
        print(f'         "env": {{ "CODEDTHEMES_TOKEN": "{client.token}" }}')
        print('       }')
        print('     },')
        print('     "inputs": []')
        print('   }\n')

        # ---------------- CURSOR ----------------
        print("🔹 Cursor")
        print("   Settings → Features → MCP Servers\n")

        print('   {')
        print('     "mcpServers": {')
        print('       "code-theme-mcp": {')
        print('         "transport": "sse",')
        print('         "url": "https://mcp.codedthemes.com/api/mcp",')
        print(f'         "env": {{ "CODEDTHEMES_TOKEN": "{client.token}" }}')
        print('       }')
        print('     }')
        print('   }\n')

        print("✔ Once saved, your AI assistant will detect available tools automatically.\n")

        print('💡 Example: "Update the primary color to deep purple"')

        print("="*60)
        
    except Exception as e:
        print(f"✖ Error during initialization: {e}")
        sys.exit(1)


def handle_apply(query: str):
    """
    Plans and executes changes based on a natural language query.
    """
    try:
        repo_root = detect_repo_root()
        repo_abs_path = os.path.abspath(repo_root)
        repo_key = repo_abs_path.lower().replace(os.sep, "/")
        print(f"🔍 Found repository at {repo_root}")
        
        client = MCPClient()
        if not client.token:
            print("✖ Not logged in. Please run 'codedthemes login' first.")
            sys.exit(1)

        user_email = "unknown_user"
        try:
            decoded = jwt.decode(client.token, options={"verify_signature": False})
            user_email = decoded.get("email", "unknown_user")
        except:
            pass

        sync_manager = SyncManager()
        config = load_config()
        last_workspaces = config.get("workspaces", {})
        workspace_id = last_workspaces.get(repo_key)
        
        # Verify or re-initialize workspace
        if workspace_id:
            try:
                check = client.call("check_workspace", {"workspace_id": workspace_id})
                if isinstance(check, dict) and check.get("status") == "error" and check.get("message") == "WORKSPACE_EVICTED":
                    print("\n⚠ Your workspace is inactive.")
                    print("It was unloaded from the server due to 30 minutes of inactivity.")
                    print("\nRun '\033[1mcodedthemes init\033[0m' to restore your workspace.\n")
                    sys.exit(0)
                
                if isinstance(check, dict) and check.get("status") == "ok":
                    # print(f"✔ Using active workspace: {workspace_id}")
                    pass
                else:
                    workspace_id = None
            except Exception as e:
                if "WORKSPACE_EVICTED" in str(e):
                    print("\n⚠ Your workspace is inactive.")
                    print("It was unloaded from the server due to 30 minutes of inactivity.")
                    print("\nRun '\033[1mcodedthemes init\033[0m' to restore your workspace.\n")
                    sys.exit(0)
                workspace_id = None


        if not workspace_id:
            print("📦 Zipping and uploading repository (this may take a moment)...")
            upload_result = client.upload_workspace(repo_abs_path, user_email)
            workspace_id = upload_result.get("workspace_id")
            last_workspaces[repo_key] = workspace_id
            config["workspaces"] = last_workspaces
            save_config(config)
            sync_manager.update_sync_state(repo_abs_path, workspace_id, user_email)

        # 1. Repository Analysis
        print("🚀 Analyzing repository...")
        analysis = client.call("repo_analyzer", {
            "repo_path": repo_abs_path,
            "workspace_id": workspace_id
        })

        if isinstance(analysis, dict) and analysis.get("status") == "error":
            print(f"✖ Analysis failed: {analysis.get('message', 'Unknown error')}")
            return
        
        if isinstance(analysis, str):
            if "Analysis Skipped" in analysis:
                print("✔ Repository is up-to-date. Skipping upload.")
            else:
                print(f"✔ {analysis}")

        # 2. Planning
        print("🔍 Detecting local changes...")
        local_changes = sync_manager.get_changed_files(repo_abs_path, user_email)
        if local_changes:
            print(f"   Detected {len(local_changes)} files changed locally since last apply.")

        print("🧠 Planning changes...")
        plan = client.call("plan_changes", {
            "query": query,
            "workspace_id": workspace_id,
            "repo_path": repo_abs_path,
            "changes_from_cli": local_changes
        })

        if plan.get("status") == "error":
            print(f"✖ Planning failed: {plan.get('message', 'Unknown error')}")
            return

        target_files = plan.get("files_to_modify", [])
        instructions = plan.get("plan_instructions", [])
        files_to_create = plan.get("files_to_create", [])
        files_to_delete = plan.get("files_to_delete", [])

        if not any([target_files, files_to_create, files_to_delete, instructions]):
            print("Information: No changes planned.")
            return

        print("\n📝 Execution Plan:")
        if instructions:
            print("Instructions:")
            for idx, inst in enumerate(instructions, 1):
                print(f"  {idx}. {inst}")
        
        if files_to_create:
            print("\nFiles to create:")
            for f in files_to_create: print(f"  + {f}")
        
        if target_files:
            print("\nFiles to modify:")
            for f in target_files: print(f"  ~ {f}")
                
        if files_to_delete:
            print("\nFiles to delete:")
            for f in files_to_delete: print(f"  - {f}")

        while True:
            choice = input("\nDo you want to proceed with this plan? (y/n): ").strip().lower()
            if choice in ['y', 'yes']: break
            if choice in ['n', 'no']:
                print("✖ Pipeline terminated by user.")
                return
            print("Please enter 'y' or 'n'.")

        # 3. Execution
        print("⚙ Executing plan...")
        result = client.call("execute_plan", {
            "query": query,
            "plan_instructions": instructions,
            "files_to_modify": target_files,
            "files_to_create": files_to_create,
            "files_to_delete": files_to_delete,
            "workspace_id": workspace_id,
            "repo_path": repo_abs_path
        })

        if not result or (isinstance(result, dict) and (result.get("status") == "error" or "detail" in result)):
             error_msg = result.get("message") or result.get("detail") if isinstance(result, dict) else "Unknown execution error"
             print(f"✖ Execution failed: {error_msg}")
             return

        # 4. Local Patching
        res_data = result
        if isinstance(result, str):
            try: res_data = json.loads(result)
            except: res_data = {}

        updates = res_data.get("updates_for_local", [])
        deletes = res_data.get("deleted_files", [])
        
        if updates or deletes:
            for item in updates:
                rel_path, code = item.get("path"), item.get("code")
                if not rel_path or code is None: continue
                abs_path = os.path.abspath(os.path.join(repo_abs_path, rel_path.replace('/', os.sep)))
                
                try:
                    os.makedirs(os.path.dirname(abs_path), exist_ok=True)
                    with open(abs_path, 'w', encoding='utf-8') as f:
                        f.write(code)
                    print(f"✔ Updated: {rel_path}")
                except Exception as e:
                    print(f"✖ Error writing {rel_path}: {e}")
                    
            for rel_path in (deletes or []):
                abs_path = os.path.normpath(os.path.join(repo_abs_path, rel_path.replace('/', os.sep)))
                if os.path.exists(abs_path) and abs_path.startswith(os.path.abspath(repo_abs_path)):
                    try:
                        if os.path.isfile(abs_path): os.remove(abs_path)
                        elif os.path.isdir(abs_path): shutil.rmtree(abs_path)
                        print(f"✔ Deleted: {rel_path}")
                    except: pass
            
            sync_manager.update_sync_state(repo_abs_path, workspace_id, user_email)
            print("✔ Local sync state updated.")

            _details_raw = res_data.get("details", [])
            details_list = _details_raw.get("report", []) if isinstance(_details_raw, dict) else (_details_raw if isinstance(_details_raw, list) else [])
            if details_list:
                print("\n📊 Integration Report:")
                for item in details_list:
                    status_icon = "✔" if item.get("success") else "✖"
                    print(f"  [{status_icon}] {item.get('file_path')}: {item.get('message', '')}")
        else:
            print(f"✔ {res_data.get('message', 'Changes applied successfully.')}")
            
    except Exception as e:
        print(f"✖ Error: {e}")
        sys.exit(1)


def main():
    try:
        from importlib.metadata import version
        __version__ = version("codedthemes-cli")
    except Exception:
        __version__ = "unknown"

    parser = argparse.ArgumentParser(prog="codedthemes", description="CodedThemes CLI client")
    parser.add_argument("-v", "--version", action="version", version=f"%(prog)s {__version__}")
    
    subparsers = parser.add_subparsers(dest="command", required=False) # Changed to False to allow --version to work alone


    login_parser = subparsers.add_parser("login", help="Login to MCP server")
    login_parser.add_argument("--server", help="MCP server URL")

    apply_parser = subparsers.add_parser("apply", help="Apply changes based on a query")
    apply_parser.add_argument("query", help="Description of changes to make")

    subparsers.add_parser("init", help="Initialize repository and sync to cloud")
    subparsers.add_parser("logout", help="Log out from current device")


    args = parser.parse_args()

    if not args.command:
        parser.print_help()
        sys.exit(0)

    if args.command == "login":
        handle_login(args.server)
    elif args.command == "init":
        handle_init()
    elif args.command == "apply":
        handle_apply(args.query)
    elif args.command == "logout":
        handle_logout()



if __name__ == "__main__":
    main()
