import linecache
import logging
import os
import socket
import sys
import traceback

from wevitos.transport import Transport

logger = logging.getLogger('wevitos')

_client = None

API_URL = 'https://wevitos.com/api/ingest/events/'


class WevitosClient:
    def __init__(self, api_key, environment='production', release='', app_root=None):
        self.api_key = api_key
        self.environment = environment
        self.release = release
        self.app_root = app_root or os.getcwd()
        self.server_name = socket.gethostname()
        self.transport = Transport(
            url=API_URL,
            api_key=self.api_key,
        )

    def notify(self, exception, extra=None, request=None, user=None):
        """Send an error report to the Wevitos server."""
        try:
            payload = self._build_payload(exception, extra=extra, request=request, user=user)
            self.transport.send(payload)
        except Exception:
            logger.exception('wevitos: failed to send error report')

    def _build_payload(self, exception, extra=None, request=None, user=None):
        exc_class = type(exception).__name__
        message = str(exception)
        stacktrace = self._extract_stacktrace(exception)

        metadata = {}
        if request:
            metadata['request'] = self._extract_request(request)
        if user:
            metadata['user'] = user
        if extra:
            metadata['extra'] = extra

        return {
            'exception_class': exc_class,
            'message': message,
            'stacktrace': stacktrace,
            'metadata': metadata,
            'server_name': self.server_name,
            'environment': self.environment,
            'release': self.release,
        }

    def _extract_stacktrace(self, exception):
        """Extract stacktrace frames with source code context."""
        tb = exception.__traceback__
        if tb is None:
            return []

        frames = []
        for frame_summary in traceback.extract_tb(tb):
            frame = {
                'file': frame_summary.filename,
                'line': frame_summary.lineno,
                'function': frame_summary.name,
            }

            # Extract source code context (5 lines before/after)
            context = self._get_context(frame_summary.filename, frame_summary.lineno)
            if context:
                frame['context'] = context

            frames.append(frame)

        return frames

    def _get_context(self, filename, lineno, context_lines=5):
        """Get source code context around a line."""
        try:
            lines = linecache.getlines(filename)
            if not lines:
                return None

            start = max(0, lineno - context_lines - 1)
            end = min(len(lines), lineno + context_lines)

            pre = [lines[i].rstrip() for i in range(start, lineno - 1)]
            line = lines[lineno - 1].rstrip() if lineno - 1 < len(lines) else ''
            post = [lines[i].rstrip() for i in range(lineno, end)]

            return {'pre': pre, 'line': line, 'post': post}
        except Exception:
            return None

    def _extract_request(self, request):
        """Extract Django request information."""
        data = {
            'method': request.method,
            'url': request.build_absolute_uri(),
        }

        # Safe headers (exclude sensitive ones)
        skip_headers = {'HTTP_COOKIE', 'HTTP_AUTHORIZATION'}
        headers = {}
        for key, value in request.META.items():
            if key.startswith('HTTP_') and key not in skip_headers:
                header_name = key[5:].replace('_', '-').title()
                headers[header_name] = value
        if headers:
            data['headers'] = headers

        return data


def init(api_key, environment='production', release='', app_root=None):
    """Initialize the wevitos client."""
    global _client
    _client = WevitosClient(
        api_key=api_key,
        environment=environment,
        release=release,
        app_root=app_root,
    )
    return _client


def notify(exception, extra=None, request=None, user=None):
    """Send an error report. Must call init() first."""
    if _client is None:
        logger.warning('wevitos: client not initialized. Call wevitos.init() first.')
        return
    _client.notify(exception, extra=extra, request=request, user=user)
