"""
PM-Agent Backend Unit Tests
"""
import os
import sys
import pytest
import tempfile
import json
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
from io import BytesIO

sys.path.insert(0, str(Path(__file__).parent.parent.parent))


class TestConfig:
    """Test configuration module"""
    
    def test_config_load(self):
        from backend.config import config
        assert config is not None
    
    def test_config_get(self):
        from backend.config import config
        assert config.get("database.url") is not None
    
    def test_config_siliconflow(self):
        from backend.config import config
        assert hasattr(config, 'siliconflow_api_key')


class TestCustomerService:
    """Test customer service"""
    
    @pytest.fixture
    def db_session(self):
        from backend.models.database import SessionLocal
        return SessionLocal()
    
    def test_list_customers(self, db_session):
        from backend.services.customer_service import CustomerService
        service = CustomerService(db_session)
        customers = service.list_all()
        assert isinstance(customers, list)
    
    def test_create_customer(self, db_session):
        from backend.services.customer_service import CustomerService
        service = CustomerService(db_session)
        customer = service.create({
            "name": f"测试客户_{os.urandom(4).hex()}",
            "keywords": "测试"
        })
        assert customer.id is not None
        assert customer.name is not None


class TestProjectService:
    """Test project service"""
    
    @pytest.fixture
    def db_session(self):
        from backend.models.database import SessionLocal
        return SessionLocal()
    
    def test_list_projects(self, db_session):
        from backend.services.project_service import ProjectService
        service = ProjectService(db_session)
        projects = service.list_all()
        assert isinstance(projects, list)
    
    def test_create_project(self, db_session):
        from backend.services.project_service import ProjectService
        service = ProjectService(db_session)
        project = service.create({
            "name": f"测试项目_{os.urandom(4).hex()}",
            "keywords": "测试"
        })
        assert project.id is not None


class TestMaterialsAPI:
    """Test materials API"""
    
    @pytest.fixture
    def client(self):
        from fastapi.testclient import TestClient
        from backend.main import app
        return TestClient(app)
    
    def test_health(self, client):
        response = client.get("/")
        assert response.status_code == 200
        assert response.json()["status"] == "running"
    
    def test_list_materials(self, client):
        response = client.get("/api/materials")
        assert response.status_code == 200
        assert "items" in response.json()
    
    def test_list_materials_pagination(self, client):
        response = client.get("/api/materials?page=1&pageSize=10")
        assert response.status_code == 200
        data = response.json()
        assert "items" in data
        assert "total" in data
    
    def test_list_customers_api(self, client):
        response = client.get("/api/customers")
        assert response.status_code == 200
    
    def test_list_projects_api(self, client):
        response = client.get("/api/projects")
        assert response.status_code == 200
    
    def test_list_templates(self, client):
        response = client.get("/api/templates")
        assert response.status_code == 200
    
    def test_get_dashboard(self, client):
        response = client.get("/api/dashboard")
        assert response.status_code == 200
        data = response.json()
        assert "stats" in data
    
    def test_get_issues(self, client):
        response = client.get("/api/issues")
        assert response.status_code == 200
        assert isinstance(response.json(), list)
    
    def test_get_issues_filter(self, client):
        response = client.get("/api/issues?type=bug")
        assert response.status_code == 200


class TestTemplatesAPI:
    """Test templates API"""
    
    @pytest.fixture
    def client(self):
        from fastapi.testclient import TestClient
        from backend.main import app
        return TestClient(app)
    
    def test_create_template(self, client):
        from backend.models.database import SessionLocal, Project
        db = SessionLocal()
        project = db.query(Project).first()
        project_id = project.id if project else 1
        
        response = client.post("/api/templates", json={
            "project_id": project_id,
            "name": f"测试模板_{os.urandom(4).hex()}",
            "template_type": "test",
            "prompt_template": "测试提示词",
            "output_format": "json",
            "fields": json.dumps([{"key": "test", "label": "测试", "field_type": "text"}])
        })
        assert response.status_code == 200


class TestGitService:
    """Test Git service"""
    
    @pytest.fixture
    def temp_repo(self):
        import git
        temp_dir = tempfile.mkdtemp()
        repo = git.Repo.init(temp_dir)
        return temp_dir
    
    def test_git_service_init(self):
        from backend.services.git_service import GitService
        service = GitService()
        assert service is not None
    
    def test_create_bug_report(self, temp_repo):
        from backend.services.git_service import GitService
        service = GitService()
        content = "# Test BUG\n\nTest content"
        result = service.create_bug_report(temp_repo, "BUG-test-001", content)
        assert result != ""
        bug_file = Path(temp_repo) / "docs" / "00-memos" / "BUG-test-001.md"
        assert bug_file.exists()
    
    def test_create_proposal(self, temp_repo):
        from backend.services.git_service import GitService
        service = GitService()
        content = "# Test Proposal\n\nTest content"
        result = service.create_proposal(temp_repo, "REQ-test-001", content)
        assert result != ""
        prop_file = Path(temp_repo) / "docs" / "04-proposals" / "REQ-test-001.md"
        assert prop_file.exists()
    
    def test_fetch_development_docs(self, temp_repo):
        from backend.services.git_service import GitService
        test_file = Path(temp_repo) / "test.md"
        test_file.write_text("# Test")
        service = GitService()
        docs = service.fetch_development_docs(temp_repo)
        assert isinstance(docs, list)


class TestSiliconFlowClient:
    """Test SiliconFlow client"""
    
    @patch('requests.post')
    def test_transcribe_audio(self, mock_post):
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "text": "测试转写内容"
        }
        mock_post.return_value = mock_response
        
        from backend.integrations.siliconflow_client import SiliconFlowClient
        client = SiliconFlowClient(api_key="test-key")
        result = client.transcribe_audio("test.mp3")
        assert result is not None
    
    @patch('requests.post')
    def test_chat(self, mock_post):
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "choices": [{"message": {"content": "测试回复"}}]
        }
        mock_post.return_value = mock_response
        
        from backend.integrations.siliconflow_client import SiliconFlowClient
        client = SiliconFlowClient(api_key="test-key")
        result = client.chat("你好")
        assert "测试回复" in result


class TestInputHandler:
    """Test input handler"""
    
    @patch('backend.integrations.siliconflow_client.SiliconFlowClient')
    def test_process_audio(self, mock_client):
        mock_instance = Mock()
        mock_instance.transcribe_audio.return_value = "测试转写"
        mock_client.return_value = mock_instance
        
        from backend.services.input_handler import InputHandler
        handler = InputHandler()
        result = handler.process("test.mp3", "audio")
        assert result is not None


class TestModels:
    """Test database models"""
    
    def test_customer_model(self):
        from backend.models.database import Customer
        assert Customer.__tablename__ == "customers"
    
    def test_project_model(self):
        from backend.models.database import Project
        assert Project.__tablename__ == "projects"
    
    def test_material_model(self):
        from backend.models.database import Material
        assert Material.__tablename__ == "materials"
    
    def test_project_template_model(self):
        from backend.models.database import ProjectTemplate
        assert ProjectTemplate.__tablename__ == "project_templates"


class TestClassifierService:
    """Test classifier service"""
    
    def test_classifier_init(self):
        from backend.services.classifier_service import ClassifierService
        service = ClassifierService()
        assert service is not None


class TestProcessingLogService:
    """Test processing log service"""
    
    @pytest.fixture
    def db_session(self):
        from backend.models.database import SessionLocal
        return SessionLocal()
    
    def test_get_recent(self, db_session):
        from backend.services.processing_log_service import ProcessingLogService
        service = ProcessingLogService(db_session)
        logs = service.get_recent(10)
        assert isinstance(logs, list)


if __name__ == "__main__":
    pytest.main([__file__, "-v", "--cov=backend", "--cov-report=term-missing"])
