"""
Test Password Reset and Email Change features for Vitaevum
Tests P1 (Password Recovery) and P2 (Email Change with confirmation) in simulated mode
"""
import pytest
import requests
import os
import uuid

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

# Test user credentials - created for P1/P2 testing
TEST_EMAIL = "test.p1p2@example.com"
TEST_PASSWORD = "testpass123"


class TestForgotPasswordFlow:
    """Tests for Forgot Password / Password Reset feature (P1)"""
    
    def test_forgot_password_valid_email_returns_reset_link(self):
        """Test that forgot password with valid email returns reset link in simulated mode"""
        response = requests.post(
            f"{BASE_URL}/api/auth/forgot-password",
            json={"email": TEST_EMAIL},
            headers={"Content-Type": "application/json"}
        )
        assert response.status_code == 200
        data = response.json()
        assert "message" in data
        # In simulated mode, resetLink should be present
        assert "resetLink" in data
        assert data["resetLink"] is not None
        assert "/reset-password?token=" in data["resetLink"]
    
    def test_forgot_password_nonexistent_email_hides_user_existence(self):
        """Test that forgot password with non-existent email doesn't reveal user existence (security)"""
        response = requests.post(
            f"{BASE_URL}/api/auth/forgot-password",
            json={"email": "nonexistent_user_xyz@example.com"},
            headers={"Content-Type": "application/json"}
        )
        assert response.status_code == 200
        data = response.json()
        assert "message" in data
        # Should NOT include reset link for non-existent users
        assert data.get("resetLink") is None
    
    def test_verify_reset_token_invalid_returns_400(self):
        """Test that verify-reset-token with invalid token returns 400"""
        response = requests.get(f"{BASE_URL}/api/auth/verify-reset-token/invalid-token-xyz")
        assert response.status_code == 400
        data = response.json()
        assert "detail" in data
        assert "invalide" in data["detail"].lower()
    
    def test_verify_reset_token_valid_returns_200(self):
        """Test complete flow: forgot password -> verify token"""
        # Step 1: Request password reset
        forgot_response = requests.post(
            f"{BASE_URL}/api/auth/forgot-password",
            json={"email": TEST_EMAIL},
            headers={"Content-Type": "application/json"}
        )
        assert forgot_response.status_code == 200
        data = forgot_response.json()
        reset_link = data.get("resetLink")
        assert reset_link is not None
        
        # Extract token from link
        token = reset_link.split("token=")[1] if "token=" in reset_link else None
        assert token is not None
        
        # Step 2: Verify the token
        verify_response = requests.get(f"{BASE_URL}/api/auth/verify-reset-token/{token}")
        assert verify_response.status_code == 200
        verify_data = verify_response.json()
        assert verify_data.get("valid") == True
    
    def test_reset_password_invalid_token_returns_400(self):
        """Test that reset-password with invalid token returns 400"""
        response = requests.post(
            f"{BASE_URL}/api/auth/reset-password",
            json={"token": "invalid-token-xyz", "newPassword": "newpassword123"},
            headers={"Content-Type": "application/json"}
        )
        assert response.status_code == 400
        data = response.json()
        assert "detail" in data


class TestEmailChangeFlow:
    """Tests for Email Change feature (P2)"""
    
    @pytest.fixture
    def auth_token(self):
        """Get authentication token for test user"""
        response = requests.post(
            f"{BASE_URL}/api/auth/login",
            json={"email": TEST_EMAIL, "password": TEST_PASSWORD},
            headers={"Content-Type": "application/json"}
        )
        if response.status_code == 200:
            return response.json().get("token")
        pytest.skip("Authentication failed - cannot test email change")
    
    def test_request_email_change_requires_auth(self):
        """Test that request-email-change requires authentication"""
        response = requests.post(
            f"{BASE_URL}/api/auth/request-email-change",
            json={"newEmail": "new@example.com", "password": "test123"},
            headers={"Content-Type": "application/json"}
        )
        assert response.status_code in [401, 403]
    
    def test_request_email_change_wrong_password_returns_401(self, auth_token):
        """Test that request-email-change with wrong password returns 401"""
        response = requests.post(
            f"{BASE_URL}/api/auth/request-email-change",
            json={"newEmail": "new@example.com", "password": "wrongpassword"},
            headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer {auth_token}"
            }
        )
        assert response.status_code == 401
        data = response.json()
        assert "detail" in data
        assert "mot de passe" in data["detail"].lower()
    
    def test_request_email_change_valid_returns_confirmation_link(self, auth_token):
        """Test that request-email-change with correct credentials returns confirmation link in simulated mode"""
        # Use a unique email to avoid conflicts
        unique_email = f"test_new_{uuid.uuid4().hex[:8]}@example.com"
        response = requests.post(
            f"{BASE_URL}/api/auth/request-email-change",
            json={"newEmail": unique_email, "password": TEST_PASSWORD},
            headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer {auth_token}"
            }
        )
        assert response.status_code == 200
        data = response.json()
        assert "message" in data
        # In simulated mode, confirmationLink should be present
        assert "confirmationLink" in data
        assert data["confirmationLink"] is not None
        assert "/confirm-email?token=" in data["confirmationLink"]
    
    def test_confirm_email_change_invalid_token_returns_400(self):
        """Test that confirm-email-change with invalid token returns 400"""
        response = requests.post(
            f"{BASE_URL}/api/auth/confirm-email-change",
            json={"token": "invalid-token-xyz"},
            headers={"Content-Type": "application/json"}
        )
        assert response.status_code == 400
        data = response.json()
        assert "detail" in data


class TestLoginPageHasForgotPasswordLink:
    """Test that login page has forgot password functionality"""
    
    def test_login_endpoint_exists(self):
        """Test that login endpoint is functional"""
        response = requests.post(
            f"{BASE_URL}/api/auth/login",
            json={"email": TEST_EMAIL, "password": TEST_PASSWORD},
            headers={"Content-Type": "application/json"}
        )
        assert response.status_code == 200
        data = response.json()
        assert "token" in data
        assert "user" in data


class TestSettingsPageEmailChange:
    """Test that settings page has email change functionality"""
    
    @pytest.fixture
    def auth_token(self):
        """Get authentication token for test user"""
        response = requests.post(
            f"{BASE_URL}/api/auth/login",
            json={"email": TEST_EMAIL, "password": TEST_PASSWORD},
            headers={"Content-Type": "application/json"}
        )
        if response.status_code == 200:
            return response.json().get("token")
        pytest.skip("Authentication failed")
    
    def test_user_can_access_settings_data(self, auth_token):
        """Test that authenticated user can access their profile data (required for settings)"""
        response = requests.get(
            f"{BASE_URL}/api/auth/me",
            headers={"Authorization": f"Bearer {auth_token}"}
        )
        assert response.status_code == 200
        data = response.json()
        assert "email" in data
        assert "name" in data
