//! Integration smoke tests for the structured-output trait + parser.

use klieo_core::error::Error;
use klieo_core::{parse_structured, KlieoResponse};
use serde::Deserialize;
use serde_json::json;

#[derive(Debug, Deserialize, PartialEq)]
struct SimpleType {
    name: String,
}

impl KlieoResponse for SimpleType {
    fn json_schema() -> serde_json::Value {
        json!({
            "type": "object",
            "properties": { "name": { "type": "string" } },
            "required": ["name"],
        })
    }
}

#[test]
fn parse_plain_round_trips() {
    let s: SimpleType = parse_structured(r#"{"name": "foo"}"#).unwrap();
    assert_eq!(s, SimpleType { name: "foo".into() });
}

#[test]
fn parse_strips_json_tagged_fence() {
    let raw = "```json\n{\"name\": \"bar\"}\n```";
    let s: SimpleType = parse_structured(raw).unwrap();
    assert_eq!(s, SimpleType { name: "bar".into() });
}

#[test]
fn parse_strips_bare_fence() {
    let raw = "```\n{\"name\": \"baz\"}\n```";
    let s: SimpleType = parse_structured(raw).unwrap();
    assert_eq!(s, SimpleType { name: "baz".into() });
}

#[test]
fn parse_strips_surrounding_whitespace() {
    let raw = "   \n  {\"name\": \"qux\"}   \n";
    let s: SimpleType = parse_structured(raw).unwrap();
    assert_eq!(s, SimpleType { name: "qux".into() });
}

#[test]
fn parse_rejects_malformed_json() {
    let err = parse_structured::<SimpleType>("totally not json").unwrap_err();
    match err {
        Error::BadResponse(msg) => {
            // Position-only diagnostic — the original parser body is
            // intentionally NOT echoed (compliance / PII).
            assert!(
                msg.contains("line") && msg.contains("col"),
                "expected line/col diagnostic, got: {msg}"
            );
            assert!(
                !msg.contains("totally not json"),
                "raw input bytes must not appear in the error: {msg}"
            );
        }
        other => panic!("expected BadResponse, got {other:?}"),
    }
}

#[test]
fn parse_structured_rejects_input_above_size_cap() {
    // 2 MiB — well above the 1 MiB cap.
    let huge = "a".repeat(2 * 1024 * 1024);
    let err = parse_structured::<SimpleType>(&huge).unwrap_err();
    match err {
        Error::BadResponse(msg) => {
            assert!(
                msg.contains("cap") || msg.contains("exceeds"),
                "expected size-cap diagnostic, got: {msg}"
            );
        }
        other => panic!("expected BadResponse, got {other:?}"),
    }
}

#[test]
fn bad_response_is_not_retryable() {
    let err = parse_structured::<SimpleType>("[]").unwrap_err();
    assert!(!err.retryable());
}

#[test]
fn json_schema_describes_shape() {
    let schema = SimpleType::json_schema();
    assert_eq!(schema["type"], "object");
    assert_eq!(schema["properties"]["name"]["type"], "string");
}
