import json
import subprocess
from pathlib import Path
from typing import Any

from sqlalchemy.orm import Session

from app.config import settings
from app.core.exceptions import AppException
from common_logging import get_logger

logger = get_logger(__name__)


class TenantImportService:

    def __init__(self, db: Session):
        self.db = db

    def import_postgresql(self, tenant_id: int, export_dir: Path) -> dict[str, Any]:
        from sqlalchemy import text

        schema_name = f"tenant_{tenant_id}"
        from urllib.parse import urlparse

        parsed = urlparse(settings.DATABASE_URL)
        db_host = parsed.hostname or "localhost"
        db_port = parsed.port or 5432
        db_name = parsed.path.lstrip("/")
        db_user = parsed.username
        db_password = parsed.password
        self.db.execute(text(f"CREATE SCHEMA IF NOT EXISTS {schema_name}"))
        self.db.commit()
        env = {"PGPASSWORD": db_password}
        import shutil

        psql = shutil.which("psql") or "/opt/homebrew/opt/postgresql@15/bin/psql"
        schema_file = export_dir / "postgresql" / "tenant_1.sql"
        if schema_file.exists():
            with open(schema_file) as f:
                sql_content = f.read()
            sql_content = sql_content.replace("tenant_1", schema_name)
            import tempfile

            with tempfile.NamedTemporaryFile(mode="w", suffix=".sql", delete=False) as tmp:
                tmp.write(sql_content)
                tmp_file = tmp.name
            try:
                cmd = [
                    psql,
                    "-h",
                    db_host,
                    "-p",
                    str(db_port),
                    "-U",
                    db_user,
                    "-d",
                    db_name,
                    "-f",
                    tmp_file,
                ]
                result = subprocess.run(cmd, env=env, capture_output=True, text=True)
                if result.returncode != 0:
                    raise AppException(f"PostgreSQL import failed: {result.stderr}")
            finally:
                import os

                os.unlink(tmp_file)
        public_file = export_dir / "postgresql" / "public_tenant_data.sql"
        if public_file.exists():
            cmd = [
                psql,
                "-h",
                db_host,
                "-p",
                str(db_port),
                "-U",
                db_user,
                "-d",
                db_name,
                "-f",
                str(public_file),
            ]
            result = subprocess.run(cmd, env=env, capture_output=True, text=True)
        return {"status": "success"}

    def import_neo4j(self, export_dir: Path) -> dict[str, Any]:
        from app.services.graph.neo4j_client import Neo4jClient

        cypher_file = export_dir / "neo4j" / "import.cypher"
        if not cypher_file.exists():
            return {"status": "skipped"}
        neo4j_client = Neo4jClient()
        with open(cypher_file, encoding="utf-8") as f:
            statements = f.read().split(";\n")
        with neo4j_client.get_session() as session:
            for stmt in statements:
                if stmt.strip():
                    session.run(stmt)
        return {"status": "success"}

    def import_milvus(self, export_dir: Path) -> dict[str, Any]:
        from pymilvus import Collection, connections

        vectors_file = export_dir / "milvus" / "vectors.json"
        if not vectors_file.exists():
            return {"status": "skipped"}
        connections.connect(host=settings.MILVUS_HOST, port=settings.MILVUS_PORT)
        collection = Collection("document_vectors")
        with open(vectors_file, encoding="utf-8") as f:
            vectors_data = json.load(f)
        if vectors_data:
            collection.insert(vectors_data)
        return {"status": "success", "count": len(vectors_data)}

    def import_files(self, export_dir: Path) -> dict[str, Any]:
        from app.services.storage.minio import MinioService

        files_dir = export_dir / "files"
        if not files_dir.exists():
            return {"status": "skipped"}
        minio = MinioService(
            endpoint=settings.MINIO_ENDPOINT,
            access_key=settings.MINIO_ACCESS_KEY,
            secret_key=settings.MINIO_SECRET_KEY,
            secure=settings.MINIO_SECURE,
        )
        uploaded = 0
        for file_path in files_dir.rglob("*"):
            if file_path.is_file():
                object_name = str(file_path.relative_to(files_dir))
                minio.upload_file(
                    bucket_name=settings.MINIO_BUCKET,
                    object_name=object_name,
                    file_path=str(file_path),
                )
                uploaded += 1
        return {"status": "success", "uploaded": uploaded}
