# http_file_importer.py
#
# Copyright 2025 Pavel Baksy
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later

import re
from dataclasses import dataclass, field
from typing import Dict, List, Optional

HTTP_METHODS = frozenset({
    'GET', 'POST', 'PUT', 'DELETE', 'PATCH',
    'HEAD', 'OPTIONS', 'TRACE', 'CONNECT',
})


@dataclass
class HttpFileRequest:
    name: str
    method: str
    url: str
    headers: Dict[str, str]
    body: str


@dataclass
class HttpFileParseResult:
    requests: List[HttpFileRequest] = field(default_factory=list)
    variables: Dict[str, str] = field(default_factory=dict)
    error: Optional[str] = None


def parse_http_file(content: str) -> HttpFileParseResult:
    """Parse an IntelliJ .http / .rest file into a list of requests."""
    result = HttpFileParseResult()

    if not content or not content.strip():
        result.error = "File is empty"
        return result

    # Split file into named blocks at each "###" separator line
    blocks: list[tuple[str, list[str]]] = []
    current_name = ""
    current_lines: list[str] = []

    for line in content.splitlines():
        if re.match(r'^###', line):
            blocks.append((current_name, current_lines))
            current_name = line[3:].strip()
            current_lines = []
        else:
            current_lines.append(line)
    blocks.append((current_name, current_lines))

    for block_name, block_lines in blocks:
        _collect_variables(block_lines, result.variables)
        req = _parse_block(block_name, block_lines)
        if req is not None:
            result.requests.append(req)

    if not result.requests:
        result.error = "No HTTP requests found in this file"

    return result


def build_http_request(req: HttpFileRequest):
    """Convert an HttpFileRequest into an HttpRequest model object."""
    from .models import HttpRequest

    body = req.body
    syntax = 'RAW'
    if body.lstrip().startswith('{'):
        syntax = 'JSON'
    elif body.lstrip().startswith('<') and not body.lstrip().startswith('< '):
        syntax = 'XML'

    return HttpRequest(
        method=req.method,
        url=req.url,
        headers=req.headers,
        body=body,
        syntax=syntax,
    )


# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------

def _collect_variables(lines: list[str], variables: dict) -> None:
    """Extract @name = value file-level variable definitions."""
    for line in lines:
        m = re.match(r'^@(\w+)\s*=\s*(.+)', line.strip())
        if m:
            variables[m.group(1)] = m.group(2).strip()


def _parse_block(name: str, lines: list[str]) -> Optional[HttpFileRequest]:
    """Parse one request block. Returns None if no valid request line found."""
    # Find the request line (METHOD URL), skipping comments and @variables
    req_idx: Optional[int] = None
    for i, line in enumerate(lines):
        stripped = line.strip()
        if not stripped:
            continue
        if stripped.startswith('#') or stripped.startswith('//'):
            continue
        if stripped.startswith('@'):
            continue
        parts = stripped.split(None, 1)
        if parts and parts[0].upper() in HTTP_METHODS:
            req_idx = i
            break
        # Any other non-blank, non-comment line before METHOD — not a request block
        break

    if req_idx is None:
        return None

    method, url = _split_request_line(lines[req_idx].strip())

    # Parse headers: lines after req_idx until blank line or response handler
    headers: Dict[str, str] = {}
    body_start = len(lines)
    i = req_idx + 1

    while i < len(lines):
        line = lines[i]
        stripped = line.strip()

        if not stripped:
            body_start = i + 1
            break
        if stripped.startswith('#') or stripped.startswith('//'):
            i += 1
            continue
        if stripped.startswith('>'):
            break
        if ':' in stripped:
            key, _, value = stripped.partition(':')
            headers[key.strip()] = value.strip()
        i += 1

    # Parse body: everything until a response handler line or end
    body_lines: list[str] = []
    for line in lines[body_start:]:
        if line.strip().startswith('>'):
            break
        # Skip file-include lines (< ./file.json) — not supported
        if re.match(r'^<\s+\S', line):
            continue
        body_lines.append(line)

    # Strip trailing blank lines from body
    while body_lines and not body_lines[-1].strip():
        body_lines.pop()

    body = '\n'.join(body_lines)

    if not name:
        name = _shorten(url)

    return HttpFileRequest(name=name, method=method, url=url, headers=headers, body=body)


def _split_request_line(line: str) -> tuple[str, str]:
    parts = line.split(None, 1)
    method = parts[0].upper()
    url = parts[1].strip() if len(parts) > 1 else ""
    return method, url


def _shorten(url: str, limit: int = 60) -> str:
    return url if len(url) <= limit else url[:limit - 1] + '…'
