#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) Huawei Technologies Co., Ltd. 2025-2026. All rights reserved.
# MindIE is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

import os
import tempfile
from unittest.mock import Mock, patch

import pytest
import requests
from motor.common.http.http_client import SafeHTTPSClient
from motor.config.tls_config import TLSConfig


@pytest.fixture
def base_url():
    return "api.example.com"


@pytest.fixture
def cert_files():
    """test certificate files"""
    with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.crt') as cert_file:
        cert_file.write("test_cert_content")
    with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.key') as key_file:
        key_file.write("test_key_content")
    with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.ca') as ca_file:
        ca_file.write("test_ca_content")

    yield cert_file.name, key_file.name, ca_file.name

    # clear file
    os.unlink(cert_file.name)
    os.unlink(key_file.name)
    os.unlink(ca_file.name)


def test_init_with_valid_parameters(base_url, cert_files):
    """test init with valid parameters"""
    cert_file, key_file, ca_file = cert_files

    tls_config = TLSConfig(
        enable_tls=True,
        cert_file=cert_file,
        key_file=key_file,
        ca_file=ca_file
    )

    client = SafeHTTPSClient(
        address=base_url,
        tls_config=tls_config,
        timeout=10
    )

    assert client.base_url == f"https://{base_url}"
    assert client.timeout == 10
    assert 'User-Agent' in client.session.headers
    assert client.session.headers['User-Agent'] == 'Secure-HTTPS-Client/1.0'


def test_init_with_missing_cert_files(base_url):
    """test init with missing cert files"""
    tls_config = TLSConfig(
        enable_tls=True,
        cert_file="nonexistent.crt",
        key_file="nonexistent.key"
    )
    # CertUtil.create_ssl_context returns None if cert files don't exist, 
    # but client can still be initialized (SSL will fail at runtime)
    client = SafeHTTPSClient(
        address=base_url,
        tls_config=tls_config
    )
    # Client should still initialize, but SSL context creation may have failed
    assert client.base_url == f"https://{base_url}"
    assert client.protocol == 'https://'


def test_init_without_certificates(base_url):
    """test init without certs"""
    client = SafeHTTPSClient(address=base_url)

    assert client.base_url == f"http://{base_url}"
    assert client.protocol == 'http://'


def test_url_construction(base_url):
    """test url construction"""
    client = SafeHTTPSClient(address=base_url)

    client_with_slash = SafeHTTPSClient(address=base_url + "/")
    assert client_with_slash.base_url == f"http://{base_url}"

    with patch.object(client.session, 'request') as mock_request:
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"success": True}
        mock_request.return_value = mock_response

        client.get("/test-endpoint")
        called_url = mock_request.call_args[1]['url']
        assert called_url == f"http://{base_url}/test-endpoint"

        client.get("test-endpoint")
        called_url = mock_request.call_args[1]['url']
        assert called_url == f"http://{base_url}/test-endpoint"


@pytest.mark.parametrize("method", ['GET', 'POST'])
def test_successful_requests(base_url, method):
    """test successful requests"""
    client = SafeHTTPSClient(address=base_url)

    with patch.object(client.session, 'request') as mock_request:
        expected_response = {"status": "success", "data": "test"}
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = expected_response
        mock_request.return_value = mock_response

        if method == 'GET':
            response = client.get("/test", params={"key": "value"})
        else:
            response = client.post("/test", data={"key": "value"})

        assert response == expected_response

        mock_request.assert_called_once()
        call_kwargs = mock_request.call_args[1]
        assert call_kwargs['method'] == method
        assert call_kwargs['url'] == f"http://{base_url}/test"


def test_ssl_error_handling(base_url):
    """test ssl error handling"""
    client = SafeHTTPSClient(address=base_url)

    with patch.object(client.session, 'request') as mock_request:
        mock_request.side_effect = requests.exceptions.SSLError("SSL certificate verification failed")

        with pytest.raises(Exception, match="SSL verify failed:"):
            client.get("/test")


def test_http_error_handling(base_url):
    """test http error handling"""
    client = SafeHTTPSClient(address=base_url)

    with patch.object(client.session, 'request') as mock_request:
        mock_response = Mock()
        mock_response.status_code = 404
        mock_response.text = "Not Found"
        mock_request.side_effect = requests.exceptions.HTTPError(response=mock_response)

        with pytest.raises(Exception, match="http response error 404"):
            client.get("/test")


def test_generic_exception_handling(base_url):
    """test generic exception handling"""
    client = SafeHTTPSClient(address=base_url)

    with patch.object(client.session, 'request') as mock_request:
        mock_request.side_effect = Exception("Generic error")

        with pytest.raises(Exception, match="send request .* error:"):
            client.get("/test")


def test_context_manager(base_url):
    """test context manager"""
    with patch.object(requests.Session, 'close') as mock_close:
        with SafeHTTPSClient(address=base_url) as client:
            assert isinstance(client, SafeHTTPSClient)

        mock_close.assert_called_once()


def test_close_method(base_url):
    """test close method"""
    client = SafeHTTPSClient(address=base_url)

    with patch.object(client.session, 'close') as mock_close:
        client.close()
        mock_close.assert_called_once()


def test_request_timeout(base_url):
    """test request timeout"""
    client = SafeHTTPSClient(address=base_url, timeout=3.5)

    with patch.object(client.session, 'request') as mock_request:
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {}
        mock_request.return_value = mock_response

        client.get("/test")

        call_kwargs = mock_request.call_args[1]
        assert call_kwargs['timeout'] == 3.5