from pathlib import Path
import asyncio
from types import SimpleNamespace

import pytest


def test_vendor_profiles_cover_the_supported_growth_matrix():
    from app.core.olt_vendor_profiles import get_vendor_profile, vendor_profiles_for_ui

    profiles = vendor_profiles_for_ui()
    keys = {profile["key"] for profile in profiles}
    assert keys == {"zte-c320", "cdata-fd16", "cdata-fd1601s-b1", "huawei-ma5800", "fiberhome-an5516", "nokia-isam", "hsgq-generic", "vsol-generic", "global-generic"}
    assert get_vendor_profile("ZTE", "C320").execution_state == "preview_supported"
    assert get_vendor_profile("C-DATA", "FD1601S-B1").discovery_state == "ready"
    assert get_vendor_profile("Huawei", "MA5800").execution_state == "unsupported"
    assert get_vendor_profile("unknown", "x") is None


def test_installation_form_uses_registered_devices_and_dynamic_vendor_fields():
    template = (Path(__file__).parents[1] / "app" / "templates" / "add_customer.html").read_text(encoding="utf-8")
    assert 'name="olt_device_id"' in template
    assert 'name="mikrotik_device_id"' in template
    assert 'name="olt_fields_json"' in template
    assert "vendorProfiles" in template
    assert "syncOltProfile" in template


def test_device_setup_guide_links_the_safe_input_sequence():
    template = (Path(__file__).parents[1] / "app" / "templates" / "devices.html").read_text(encoding="utf-8")
    assert 'id="panduan-uji"' in template
    for path in ("/odps", "/service-packages", "/add-customer"):
        assert f'href="{path}"' in template
    assert "Tidak menghubungkan atau mengirim konfigurasi ke perangkat fisik" in template


def test_device_registry_exposes_safe_connection_test_controls():
    root = Path(__file__).parents[1]
    template = (root / "app" / "templates" / "devices.html").read_text(encoding="utf-8")
    routes = (root / "app" / "routes" / "devices.py").read_text(encoding="utf-8")
    assert template.count("Cek Port Management") == 2
    assert "Test Koneksi" not in template
    assert "showConnectionTestStart" in template
    assert "fetch(form.action" in template
    assert "return false" in template
    assert "showConnectionTestResult" not in template
    assert "role=\"status\"" not in template
    assert '/test-connection' in template
    assert '@router.post("/devices/{device_kind}/{device_id}/test-connection")' in routes
    assert "await _probe_tcp" in routes


@pytest.mark.asyncio
async def test_tcp_probe_opens_and_closes_a_tcp_socket(monkeypatch):
    from app.routes.devices import _probe_tcp

    seen = {}

    class Writer:
        def close(self):
            seen["closed"] = True

        async def wait_closed(self):
            seen["waited"] = True

    async def fake_open_connection(host, port):
        seen["target"] = (host, port)
        return object(), Writer()

    monkeypatch.setattr(asyncio, "open_connection", fake_open_connection)
    ok, detail = await _probe_tcp("192.0.2.10", 8728)

    assert ok is True
    assert detail is None
    assert seen == {"target": ("192.0.2.10", 8728), "closed": True, "waited": True}


@pytest.mark.asyncio
async def test_connection_endpoint_returns_json_without_redirect(monkeypatch):
    from app.routes import devices

    device = SimpleNamespace(id=1, name="MIKROTIK-UJI", host="192.0.2.10", api_port=8728, is_active=True)

    class FakeDB:
        async def get(self, model, device_id):
            return device

    async def connected(host, port):
        return True, None

    monkeypatch.setattr(devices, "_probe_tcp", connected)
    response = await devices.test_connection("mikrotik", 1, FakeDB())

    assert response.status_code == 200
    assert response.media_type == "application/json"
    assert response.body == b'{"ok":true,"message":"MIKROTIK-UJI: port management 192.0.2.10:8728 dapat dijangkau pada level TCP. Protokol dan login perangkat belum diuji."}'


def test_multi_vendor_models_record_assignments_and_audit_events():
    from app.models.models import Customer, ODP, OLTDevice, MikrotikDevice, ProvisioningEvent, ProvisioningJob

    assert hasattr(Customer, "olt_device_id") and hasattr(Customer, "mikrotik_device_id")
    assert hasattr(Customer, "olt_fields_json")
    assert hasattr(ODP, "mikrotik_device_id")
    assert hasattr(OLTDevice, "management_protocol")
    assert hasattr(MikrotikDevice, "credential_id")
    assert hasattr(OLTDevice, "credential_id")
    assert hasattr(ProvisioningJob, "payload_summary")
    assert hasattr(ProvisioningEvent, "adapter_key")
