import socket
import logging
from .base import Finding

logger = logging.getLogger(__name__)

CHECK_NAME = 'public_ports'
TIMEOUT = 3

PORT_INFO = {
    22:   ('warning',  'SSH',     'SSH exposed to the internet. Ensure key-only auth and restrict access.'),
    23:   ('critical', 'Telnet',  'Telnet (cleartext) is exposed to the internet. Disable immediately.'),
    25:   ('warning',  'SMTP',    'SMTP port exposed. Could be used for spam relay if misconfigured.'),
    53:   ('warning',  'DNS',     'DNS port open. Run the DNS resolver check to confirm if recursive queries are allowed.'),
    80:   ('info',     'HTTP',    'HTTP port open. Expected for public web services.'),
    443:  ('info',     'HTTPS',   'HTTPS port open. Expected for public web services.'),
    3306: ('critical', 'MySQL',   'MySQL database port exposed to the internet. Restrict access immediately.'),
    5432: ('critical', 'Postgres','PostgreSQL database port exposed to the internet. Restrict access immediately.'),
    6379: ('critical', 'Redis',   'Redis port exposed to the internet. Redis has no auth by default — critical risk.'),
    8080: ('warning',  'HTTP-alt','Alternate HTTP port 8080 is open. Verify this is intentional.'),
    8443: ('warning',  'HTTPS-alt','Alternate HTTPS port 8443 is open. Verify this is intentional.'),
}


def _tcp_open(host: str, port: int) -> bool:
    try:
        with socket.create_connection((host, port), timeout=TIMEOUT):
            return True
    except (OSError, socket.timeout):
        return False


def run(profile) -> list:
    findings = []
    host = profile.public_ip
    raw = {'public_ip': host, 'open_ports': []}

    for port, (severity, label, detail) in PORT_INFO.items():
        if _tcp_open(host, port):
            raw['open_ports'].append(port)
            findings.append(Finding(
                check_name=CHECK_NAME,
                severity=severity,
                title=f'Port {port} ({label}) open on public IP {host}',
                detail=detail,
                raw={'public_ip': host, 'port': port},
            ))

    if not findings:
        findings.append(Finding(
            check_name=CHECK_NAME,
            severity='ok',
            title=f'No high-risk ports open on public IP {host}',
            detail='All probed ports are closed or filtered.',
            raw=raw,
        ))

    return findings
