"""
Backend API Tests for Queen City Auto Sourcing
Tests: Authentication, Part Requests, Inventory, Dashboard Stats, User flow, Quotes, Orders, Invoices, Shipments
"""

import pytest
import requests
import os
import uuid
from datetime import datetime

BASE_URL = os.environ.get('REACT_APP_BACKEND_URL', '').rstrip('/')

# Admin credentials
ADMIN_USERNAME = "admin"
ADMIN_PASSWORD = "queencity2024"

# Test data prefix for cleanup
TEST_PREFIX = "TEST_"

@pytest.fixture(scope="module")
def api_client():
    """Shared requests session"""
    session = requests.Session()
    session.headers.update({"Content-Type": "application/json"})
    return session

@pytest.fixture(scope="module")
def admin_token(api_client):
    """Get admin authentication token"""
    response = api_client.post(f"{BASE_URL}/api/auth/login", json={
        "username": ADMIN_USERNAME,
        "password": ADMIN_PASSWORD
    })
    if response.status_code == 200:
        return response.json().get("token")
    pytest.skip("Admin authentication failed - skipping admin tests")

@pytest.fixture(scope="module")
def admin_headers(admin_token):
    """Admin auth headers"""
    return {"Authorization": f"Bearer {admin_token}", "Content-Type": "application/json"}


class TestHealthAndBasics:
    """Basic health and API accessibility tests"""
    
    def test_inventory_public_endpoint(self, api_client):
        """Public inventory endpoint should be accessible"""
        response = api_client.get(f"{BASE_URL}/api/inventory")
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        print(f"✓ Inventory endpoint returns {len(data)} items")
    
    def test_testimonials_public_endpoint(self, api_client):
        """Public testimonials endpoint should be accessible"""
        response = api_client.get(f"{BASE_URL}/api/testimonials")
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        print(f"✓ Testimonials endpoint returns {len(data)} items")


class TestAdminAuthentication:
    """Admin authentication flow tests"""
    
    def test_admin_login_success(self, api_client):
        """Admin login with valid credentials"""
        response = api_client.post(f"{BASE_URL}/api/auth/login", json={
            "username": ADMIN_USERNAME,
            "password": ADMIN_PASSWORD
        })
        assert response.status_code == 200
        data = response.json()
        assert "token" in data
        assert data.get("username") == ADMIN_USERNAME
        assert data.get("role") == "admin"
        print("✓ Admin login successful")
    
    def test_admin_login_invalid_credentials(self, api_client):
        """Admin login with invalid credentials should fail"""
        response = api_client.post(f"{BASE_URL}/api/auth/login", json={
            "username": "wronguser",
            "password": "wrongpassword"
        })
        assert response.status_code == 401
        print("✓ Invalid admin credentials rejected")
    
    def test_admin_me_endpoint(self, api_client, admin_headers):
        """Admin me endpoint returns admin info"""
        response = api_client.get(f"{BASE_URL}/api/auth/me", headers=admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert data.get("username") == ADMIN_USERNAME
        assert data.get("role") == "admin"
        print("✓ Admin me endpoint works")


class TestDashboardStats:
    """Dashboard stats endpoint tests"""
    
    def test_dashboard_stats(self, api_client, admin_headers):
        """Dashboard stats endpoint returns all expected fields"""
        response = api_client.get(f"{BASE_URL}/api/dashboard/stats", headers=admin_headers)
        assert response.status_code == 200
        data = response.json()
        expected_fields = ["total_requests", "new_requests", "completed", "total_profit", "total_orders", "total_quotes"]
        for field in expected_fields:
            assert field in data, f"Missing field: {field}"
        print(f"✓ Dashboard stats: {data}")


class TestPartRequests:
    """Part request CRUD tests"""
    
    def test_create_part_request(self, api_client):
        """Create a public part request"""
        test_id = str(uuid.uuid4())[:8]
        payload = {
            "name": f"{TEST_PREFIX}Customer_{test_id}",
            "email": f"test_{test_id}@example.com",
            "phone": "704-555-1234",
            "vehicle_year": "2020",
            "make": "Toyota",
            "model": "Camry",
            "part_needed": f"{TEST_PREFIX}Headlight Assembly",
            "budget": "$200-300",
            "notes": "Test request"
        }
        response = api_client.post(f"{BASE_URL}/api/part-requests", json=payload)
        assert response.status_code == 200
        data = response.json()
        assert "id" in data
        assert data["status"] == "new"
        assert data["name"] == payload["name"]
        assert data["part_needed"] == payload["part_needed"]
        print(f"✓ Created part request: {data['id']}")
        return data["id"]
    
    def test_list_part_requests(self, api_client, admin_headers):
        """List all part requests (admin)"""
        response = api_client.get(f"{BASE_URL}/api/part-requests", headers=admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        print(f"✓ Listed {len(data)} part requests")
    
    def test_update_part_request_status(self, api_client, admin_headers):
        """Update part request status"""
        # First create a request
        test_id = str(uuid.uuid4())[:8]
        create_response = api_client.post(f"{BASE_URL}/api/part-requests", json={
            "name": f"{TEST_PREFIX}Update_Test_{test_id}",
            "email": f"update_{test_id}@example.com",
            "part_needed": f"{TEST_PREFIX}Brake Pads"
        })
        assert create_response.status_code == 200
        request_id = create_response.json()["id"]
        
        # Update status
        update_response = api_client.patch(
            f"{BASE_URL}/api/part-requests/{request_id}",
            json={"status": "in_progress"},
            headers=admin_headers
        )
        assert update_response.status_code == 200
        data = update_response.json()
        assert data["status"] == "in_progress"
        print(f"✓ Updated part request status to in_progress")
        
        # Verify with GET
        list_response = api_client.get(f"{BASE_URL}/api/part-requests", headers=admin_headers)
        requests = list_response.json()
        updated_req = next((r for r in requests if r["id"] == request_id), None)
        assert updated_req is not None
        assert updated_req["status"] == "in_progress"
        print("✓ Status change persisted in database")
    
    def test_update_part_request_pricing(self, api_client, admin_headers):
        """Update part request pricing and verify profit calculation"""
        # Create request
        test_id = str(uuid.uuid4())[:8]
        create_response = api_client.post(f"{BASE_URL}/api/part-requests", json={
            "name": f"{TEST_PREFIX}Pricing_Test_{test_id}",
            "email": f"pricing_{test_id}@example.com",
            "part_needed": f"{TEST_PREFIX}Engine Block"
        })
        request_id = create_response.json()["id"]
        
        # Update pricing
        update_response = api_client.patch(
            f"{BASE_URL}/api/part-requests/{request_id}",
            json={"quoted_price": 500.0, "cost_price": 300.0},
            headers=admin_headers
        )
        assert update_response.status_code == 200
        data = update_response.json()
        assert data["quoted_price"] == 500.0
        assert data["cost_price"] == 300.0
        assert data["profit"] == 200.0  # 500 - 300
        print(f"✓ Pricing updated: quoted=${data['quoted_price']}, cost=${data['cost_price']}, profit=${data['profit']}")
    
    def test_delete_part_request(self, api_client, admin_headers):
        """Delete part request"""
        # Create request
        test_id = str(uuid.uuid4())[:8]
        create_response = api_client.post(f"{BASE_URL}/api/part-requests", json={
            "name": f"{TEST_PREFIX}Delete_Test_{test_id}",
            "email": f"delete_{test_id}@example.com",
            "part_needed": f"{TEST_PREFIX}Delete Me"
        })
        request_id = create_response.json()["id"]
        
        # Delete
        delete_response = api_client.delete(
            f"{BASE_URL}/api/part-requests/{request_id}",
            headers=admin_headers
        )
        assert delete_response.status_code == 200
        print(f"✓ Deleted part request: {request_id}")


class TestUserAuthentication:
    """User registration and login tests"""
    
    def test_user_registration(self, api_client):
        """Register a new user"""
        test_id = str(uuid.uuid4())[:8]
        payload = {
            "name": f"{TEST_PREFIX}User_{test_id}",
            "email": f"testuser_{test_id}@example.com",
            "password": "testpass123",
            "phone": "704-555-4321"
        }
        response = api_client.post(f"{BASE_URL}/api/user/register", json=payload)
        assert response.status_code == 200
        data = response.json()
        assert "token" in data
        assert "user" in data
        assert data["user"]["email"] == payload["email"]
        print(f"✓ User registered: {data['user']['email']}")
        return data
    
    def test_user_registration_duplicate_email(self, api_client):
        """Duplicate email registration should fail"""
        test_id = str(uuid.uuid4())[:8]
        payload = {
            "name": f"{TEST_PREFIX}Dup_User_{test_id}",
            "email": f"dupuser_{test_id}@example.com",
            "password": "testpass123"
        }
        # First registration
        response1 = api_client.post(f"{BASE_URL}/api/user/register", json=payload)
        assert response1.status_code == 200
        
        # Second registration with same email
        response2 = api_client.post(f"{BASE_URL}/api/user/register", json=payload)
        assert response2.status_code == 400
        print("✓ Duplicate email registration rejected")
    
    def test_user_login(self, api_client):
        """User login flow"""
        test_id = str(uuid.uuid4())[:8]
        # Register first
        register_payload = {
            "name": f"{TEST_PREFIX}Login_User_{test_id}",
            "email": f"loginuser_{test_id}@example.com",
            "password": "loginpass123"
        }
        api_client.post(f"{BASE_URL}/api/user/register", json=register_payload)
        
        # Login
        login_response = api_client.post(f"{BASE_URL}/api/user/login", json={
            "email": register_payload["email"],
            "password": register_payload["password"]
        })
        assert login_response.status_code == 200
        data = login_response.json()
        assert "token" in data
        assert "user" in data
        print(f"✓ User login successful: {data['user']['email']}")
    
    def test_user_login_invalid_credentials(self, api_client):
        """User login with invalid credentials should fail"""
        response = api_client.post(f"{BASE_URL}/api/user/login", json={
            "email": "nonexistent@example.com",
            "password": "wrongpassword"
        })
        assert response.status_code == 401
        print("✓ Invalid user credentials rejected")


class TestInventory:
    """Inventory CRUD tests"""
    
    def test_list_inventory(self, api_client):
        """List inventory (public)"""
        response = api_client.get(f"{BASE_URL}/api/inventory")
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        if data:
            item = data[0]
            assert "name" in item
            assert "price" in item
            assert "category" in item
        print(f"✓ Listed {len(data)} inventory items")
    
    def test_create_inventory_item(self, api_client, admin_headers):
        """Create inventory item (admin)"""
        test_id = str(uuid.uuid4())[:8]
        payload = {
            "name": f"{TEST_PREFIX}Test Part_{test_id}",
            "description": "Test description",
            "price": 299.99,
            "original_price": 499.99,
            "vehicle_year": "2021",
            "make": "Honda",
            "model": "Accord",
            "category": "Engine",
            "condition": "OEM Used"
        }
        response = api_client.post(f"{BASE_URL}/api/inventory", json=payload, headers=admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert data["name"] == payload["name"]
        assert data["price"] == payload["price"]
        print(f"✓ Created inventory item: {data['name']}")
        return data["id"]
    
    def test_delete_inventory_item(self, api_client, admin_headers):
        """Delete inventory item (admin)"""
        # Create item first
        test_id = str(uuid.uuid4())[:8]
        create_response = api_client.post(f"{BASE_URL}/api/inventory", json={
            "name": f"{TEST_PREFIX}Delete_Part_{test_id}",
            "price": 100.0
        }, headers=admin_headers)
        item_id = create_response.json()["id"]
        
        # Delete
        delete_response = api_client.delete(f"{BASE_URL}/api/inventory/{item_id}", headers=admin_headers)
        assert delete_response.status_code == 200
        print(f"✓ Deleted inventory item: {item_id}")


class TestContacts:
    """Contact submission tests"""
    
    def test_create_contact(self, api_client):
        """Create contact submission (public)"""
        test_id = str(uuid.uuid4())[:8]
        payload = {
            "name": f"{TEST_PREFIX}Contact_{test_id}",
            "email": f"contact_{test_id}@example.com",
            "phone": "704-555-9999",
            "message": "Test contact message"
        }
        response = api_client.post(f"{BASE_URL}/api/contact", json=payload)
        assert response.status_code == 200
        data = response.json()
        assert data["name"] == payload["name"]
        assert data["email"] == payload["email"]
        print(f"✓ Created contact submission: {data['id']}")
    
    def test_list_contacts(self, api_client, admin_headers):
        """List contacts (admin)"""
        response = api_client.get(f"{BASE_URL}/api/contacts", headers=admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        print(f"✓ Listed {len(data)} contacts")


class TestVinDecoder:
    """VIN decoder tests"""
    
    def test_vin_decode_valid(self, api_client):
        """Decode valid VIN"""
        # Using a known sample VIN (2019 Toyota Camry)
        vin = "4T1B11HK2KU123456"
        response = api_client.get(f"{BASE_URL}/api/vin-decode/{vin}")
        # Note: The NHTSA API may return empty for test VINs
        assert response.status_code in [200, 400]
        if response.status_code == 200:
            data = response.json()
            assert "year" in data
            assert "make" in data
            assert "model" in data
            print(f"✓ VIN decoded: {data}")
    
    def test_vin_decode_invalid_length(self, api_client):
        """Decode invalid VIN (wrong length)"""
        response = api_client.get(f"{BASE_URL}/api/vin-decode/SHORT")
        assert response.status_code == 400
        print("✓ Invalid VIN length rejected")


class TestQuotes:
    """Quote management tests"""
    
    def test_list_quotes(self, api_client, admin_headers):
        """List all quotes (admin)"""
        response = api_client.get(f"{BASE_URL}/api/quotes", headers=admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        print(f"✓ Listed {len(data)} quotes")


class TestOrders:
    """Order management tests"""
    
    def test_list_orders(self, api_client, admin_headers):
        """List all orders (admin)"""
        response = api_client.get(f"{BASE_URL}/api/orders", headers=admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        print(f"✓ Listed {len(data)} orders")


class TestInvoices:
    """Invoice management tests"""
    
    def test_list_invoices(self, api_client, admin_headers):
        """List all invoices (admin)"""
        response = api_client.get(f"{BASE_URL}/api/invoices", headers=admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        print(f"✓ Listed {len(data)} invoices")


class TestShipments:
    """Shipment management tests"""
    
    def test_list_shipments(self, api_client, admin_headers):
        """List all shipments (admin)"""
        response = api_client.get(f"{BASE_URL}/api/shipments", headers=admin_headers)
        assert response.status_code == 200
        data = response.json()
        assert isinstance(data, list)
        print(f"✓ Listed {len(data)} shipments")


if __name__ == "__main__":
    pytest.main([__file__, "-v", "--tb=short"])
