#!/usr/bin/env python3
import json
import os
import shutil
import sys
import urllib.error
import urllib.request
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Optional


API_BASE_URL  = os.getenv("PEPPOS_BASE_URL",              "https://sandbox.pepposh.eu")
CLIENT_ID     = os.getenv("PEPPOS_CLIENT_ID",             "YOUR-API-KEY")
CLIENT_SECRET = os.getenv("PEPPOS_CLIENT_SECRET",         "YOUR-API-SECRET")

INPUT_DIR = Path(os.getenv("ISDOC_INPUT_DIR", "isdoc"))
SENT_DIR = Path(os.getenv("ISDOC_SENT_DIR", "isdoc_sent"))

@dataclass
class SendResult:
	filename: str
	sent: bool
	moved_to: Optional[str]
	document_id: Optional[str]
	final_status: Optional[str]
	queue_status: Optional[str]
	message: str


def http_json(
	method: str,
	url: str,
	headers: Optional[dict[str, str]] = None,
	payload: Optional[str] = None,
) -> tuple[int, Any]:
	req_headers = {"Accept": "application/json"}
	if headers:
		req_headers.update(headers)

	data: Optional[bytes] = None
	if payload is not None:
		if isinstance(payload, str):
			data = payload.encode("utf-8")
			req_headers["Content-Type"] = "application/xml"
		else:
			data = json.dumps(payload).encode("utf-8")
			req_headers["Content-Type"] = "application/json"

	req = urllib.request.Request(url, data=data, method=method, headers=req_headers)
	try:
		with urllib.request.urlopen(req, timeout=30) as resp:
			raw = resp.read().decode("utf-8", errors="replace")
			return resp.getcode(), (json.loads(raw) if raw else {})
	except urllib.error.HTTPError as e:
		body = e.read().decode("utf-8", errors="replace")
		try:
			parsed = json.loads(body) if body else {}
		except json.JSONDecodeError:
			parsed = {"raw": body}
		return e.code, parsed


def get_token() -> str:
	if not CLIENT_ID or not CLIENT_SECRET:
		raise RuntimeError("Missing PEPPOS_CLIENT_ID or PEPPOS_CLIENT_SECRET environment variable.")

	status, body = http_json(
		"POST",
		f"{API_BASE_URL}/api/auth/token",
		payload={
			"client_id": CLIENT_ID,
			"client_secret": CLIENT_SECRET,
			"grant_type": "client_credentials",
		},
	)
	if status != 200 or "access_token" not in body:
		raise RuntimeError(f"Token request failed ({status}): {json.dumps(body, ensure_ascii=False)}")
	return body["access_token"]


def send_isdoc_document(token: str, isdoc_path: Path) -> tuple[Optional[str], dict[str, Any]]:
	content = isdoc_path.read_text(encoding="utf-8")
	status, body = http_json(
		"POST",
		f"{API_BASE_URL}/api/documents/send/as/isdoc?wait-for-result",
		headers={
			"Authorization": f"Bearer {token}",
		},
		payload=content,
	)

	if status not in (200, 201, 202):
		return None, {"http_status": status, "response": body}

	document_id = body.get("data", {}).get("documentId") if isinstance(body, dict) else None
	return document_id, {"http_status": status, "response": body}

def main() -> int:
	if not INPUT_DIR.exists():
		print(f"Input directory not found: {INPUT_DIR}")
		return 1

	SENT_DIR.mkdir(parents=True, exist_ok=True)

	try:
		token = get_token()
	except Exception as e:
		print(f"Token error: {e}")
		return 1

	files = sorted(p for p in INPUT_DIR.glob("*.isdoc") if p.is_file())
	if not files:
		print(f"No .isdoc files found in {INPUT_DIR}")
		return 0

	results: list[SendResult] = []

	for path in files:
		try:
			document_id, send_meta = send_isdoc_document(token, path)
			if not document_id:
				results.append(
					SendResult(
						filename=path.name,
						sent=False,
						moved_to=None,
						document_id=None,
						final_status=None,
						queue_status=None,
						message=f"Send failed: {json.dumps(send_meta, ensure_ascii=False)}",
					)
				)
				continue

			status_body = send_meta.get("response") if isinstance(send_meta, dict) else {}
			final_status = status_body.get("status") if isinstance(status_body, dict) else None
			queue_status = None
			message_status = None
			if isinstance(status_body, dict):
				queue_status = (status_body.get("sendQueueStatus") or {}).get("status")
				message_status = status_body.get("messageStatus")

			is_sent = queue_status in {"sent", "delivered"} or message_status in {"sent", "delivered"}

			if is_sent:
				target = SENT_DIR / path.name
				shutil.move(str(path), str(target))
				results.append(
					SendResult(
						filename=path.name,
						sent=True,
						moved_to=str(target),
						document_id=document_id,
						final_status=final_status,
						queue_status=queue_status,
						message="Sent and moved.",
					)
				)
			else:
				results.append(
					SendResult(
						filename=path.name,
						sent=False,
						moved_to=None,
						document_id=document_id,
						final_status=final_status,
						queue_status=queue_status,
						message=f"Not sent or delivery failed: {json.dumps(status_body, ensure_ascii=False)}",
					)
				)
		except Exception as e:
			results.append(
				SendResult(
					filename=path.name,
					sent=False,
					moved_to=None,
					document_id=None,
					final_status=None,
					queue_status=None,
					message=f"Error: {e}",
				)
			)

	print("\n=== Batch result ===")
	for r in results:
		print(
			json.dumps(
				{
					"file": r.filename,
					"sent": r.sent,
					"moved_to": r.moved_to,
					"document_id": r.document_id,
					"final_status": r.final_status,
					"queue_status": r.queue_status,
					"message": r.message,
				},
				ensure_ascii=False,
			)
		)

	sent_count = sum(1 for r in results if r.sent)
	print(f"\nSent successfully: {sent_count}/{len(results)}")
	return 0 if sent_count == len(results) else 2


if __name__ == "__main__":
	sys.exit(main())
