// Copyright (c) Subzero Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::ops::Deref;
#[cfg(feature = "non-pdk")]
use std::str::FromStr;

#[cfg(feature = "non-pdk")]
use crate::{ConsensusMessage, RexId, RexUpdateResult, TargetRexProgram};
use crate::{RexUrl, RexValue, UpdateFrequency};

#[test]
#[cfg(feature = "non-pdk")]
fn test_rex_update_result_creation() {
    // Test valid creation
    let rex_id = RexId::default();
    let input_commitment = blake3::hash(b"dummy request");
    let result = RexUpdateResult::new(
        rex_id,
        42,
        b"42.5".to_vec(),
        *input_commitment.as_bytes(),
        [0; _],
        None,
        [0; _],
    );
    assert!(result.is_ok());
    let result = result.unwrap();
    assert_eq!(result.rex_id, rex_id);
    assert_eq!(result.target_timestamp, 42);
    assert_eq!(result.rex_result, b"42.5".to_vec());
    assert_eq!(result.signature, [0; 64]);

    // Test creation with too large result
    let result = RexUpdateResult::new(
        RexId::default(),
        42,
        vec![b'x'; (rialo_limits::MAX_TRANSACTION_SIZE + 1) as usize],
        *input_commitment.as_bytes(),
        [0; _],
        None,
        [0; _],
    );
    assert!(result.is_err());
}

#[test]
#[cfg(feature = "non-pdk")]
fn test_target_rex_program_from_str() {
    // Test valid targets
    assert_eq!(
        TargetRexProgram::from_str("Time").unwrap(),
        TargetRexProgram::Time
    );

    // Test invalid target
    assert!(TargetRexProgram::from_str("number").is_err());
    assert!(TargetRexProgram::from_str("invalid").is_err());
}

#[test]
fn test_update_frequency_equality() {
    assert_eq!(UpdateFrequency::OneShot, UpdateFrequency::OneShot);
    assert_eq!(UpdateFrequency::Periodic(10), UpdateFrequency::Periodic(10));
    assert_ne!(UpdateFrequency::Periodic(10), UpdateFrequency::Periodic(20));
    assert_eq!(
        UpdateFrequency::LimitedPeriodic(5, 100),
        UpdateFrequency::LimitedPeriodic(5, 100)
    );
    assert_ne!(
        UpdateFrequency::LimitedPeriodic(5, 100),
        UpdateFrequency::LimitedPeriodic(5, 200)
    );
    assert_ne!(UpdateFrequency::OneShot, UpdateFrequency::Periodic(10));
}

#[test]
#[cfg(feature = "non-pdk")]
fn test_consensus_message_serialization() {
    let input_commitment = blake3::hash(b"dummy request");
    // Test RexUpdateResult variant
    let rex_result = RexUpdateResult::new(
        Default::default(),
        42,
        b"42.5".to_vec(),
        *input_commitment.as_bytes(),
        [0; _],
        None,
        [0; _],
    )
    .unwrap();

    let message = ConsensusMessage::RexUpdateResult(Box::new(rex_result.clone()));
    let serialized = serde_json::to_string(&message).unwrap();
    let deserialized: ConsensusMessage = serde_json::from_str(&serialized).unwrap();

    match deserialized {
        ConsensusMessage::RexUpdateResult(result) => {
            assert_eq!(*result, rex_result);
        }
        _ => panic!("Wrong variant deserialized"),
    }
}

#[test]
fn test_rex_url_plain_parse_and_to_string() {
    let original = "https://api.example.com/data?key=value";
    let url: RexUrl = original.parse().unwrap();
    assert_eq!(url.to_string(), original);
}

#[test]
fn test_rex_url_encrypted_parse_and_to_string() {
    let encrypted_data = "YWJjZGVmZ2hpams=";
    let original = format!("enc://{}", encrypted_data);
    let url: RexUrl = original.parse().unwrap();
    assert_eq!(url.to_string(), original);
}

#[test]
fn test_rex_url_plain_roundtrip() {
    let test_cases = vec![
        "https://api.example.com/data",
        "https://example.com/endpoint?key=secret123",
        "https://api.service.io/v1/resource",
        "http://localhost:8080/webhook",
    ];

    for original in test_cases {
        let url: RexUrl = original.parse().unwrap();
        let roundtrip = url.to_string();
        assert_eq!(roundtrip, original, "Roundtrip failed for: {}", original);

        // Verify it's still plain after roundtrip
        let url2: RexUrl = roundtrip.parse().unwrap();
        assert!(matches!(url2.deref(), RexValue::Plain(_)));
    }
}

#[test]
fn test_rex_url_encrypted_roundtrip() {
    let test_cases = vec![
        "enc://YWJjZGVmZ2hpams=",
        "enc://dGhpcyBpcyBhIHRlc3Q=",
        "enc://bG9uZ2VyX2Jhc2U2NF9lbmNvZGVkX2RhdGFfd2l0aF9tb3JlX2NoYXJhY3RlcnM=",
    ];

    for original in test_cases {
        let url: RexUrl = original.parse().unwrap();
        let roundtrip = url.to_string();
        assert_eq!(roundtrip, original, "Roundtrip failed for: {}", original);

        // Verify it's still encrypted after roundtrip
        let url2: RexUrl = roundtrip.parse().unwrap();
        assert!(matches!(url2.deref(), RexValue::Encrypted(_)));
    }
}

#[test]
fn test_rex_url_type_preservation() {
    // Plain URL should remain plain
    let plain: RexUrl = "https://example.com".parse().unwrap();
    assert!(matches!(plain.deref(), RexValue::Plain(s) if s.as_slice() == b"https://example.com"));

    // Encrypted URL should remain encrypted (without the enc:// prefix in the inner value)
    let encrypted: RexUrl = "enc://YWJjZGVm".parse().unwrap();
    assert!(matches!(encrypted.deref(), RexValue::Encrypted(s) if s.as_slice() == b"YWJjZGVm"));
}

#[test]
fn test_rex_url_display_format() {
    // Plain URL displays as-is
    let plain: RexUrl = "https://example.com".into();
    assert_eq!(plain.to_string(), "https://example.com");

    // Encrypted URL displays with enc:// prefix
    let encrypted: RexUrl = "enc://YWJjZGVm".into();
    assert_eq!(encrypted.to_string(), "enc://YWJjZGVm");
}

#[test]
fn test_rex_url_from_string() {
    // Test From<String> implementation
    let plain = String::from("https://api.example.com");
    let url: RexUrl = plain.clone().into();
    assert_eq!(url.to_string(), plain);

    let encrypted = String::from("enc://dGVzdA==");
    let url: RexUrl = encrypted.clone().into();
    assert_eq!(url.to_string(), encrypted);
}

#[test]
fn test_rex_url_from_str() {
    // Test From<&str> implementation
    let plain: RexUrl = "https://api.example.com".into();
    assert!(matches!(plain.deref(), RexValue::Plain(_)));

    let encrypted: RexUrl = "enc://dGVzdA==".into();
    assert!(matches!(encrypted.deref(), RexValue::Encrypted(_)));
}

#[test]
#[cfg(feature = "non-pdk")]
fn test_rex_url_from_url_plain() {
    use url::Url;

    // Test plain HTTPS URL
    let url = Url::parse("https://api.example.com/data?key=value").unwrap();
    let rex_url: RexUrl = url.into();
    assert!(
        matches!(rex_url.deref(), RexValue::Plain(s) if s.as_slice() == b"https://api.example.com/data?key=value")
    );
    assert_eq!(
        rex_url.to_string(),
        "https://api.example.com/data?key=value"
    );

    // Test plain HTTP URL
    let url = Url::parse("http://localhost:8080/webhook").unwrap();
    let rex_url: RexUrl = url.into();
    assert!(matches!(rex_url.deref(), RexValue::Plain(_)));
    assert_eq!(rex_url.to_string(), "http://localhost:8080/webhook");
}

#[test]
#[cfg(feature = "non-pdk")]
fn test_rex_url_from_url_encrypted() {
    use url::Url;

    // Test encrypted URL with base64 data
    let url = Url::parse("enc://YWJjZGVmZ2hpams=").unwrap();
    let rex_url: RexUrl = url.into();

    // The internal representation should strip the "enc://" prefix
    assert!(
        matches!(rex_url.deref(), RexValue::Encrypted(s) if s.as_slice() == b"YWJjZGVmZ2hpams=")
    );

    // But the display should include it
    assert_eq!(rex_url.to_string(), "enc://YWJjZGVmZ2hpams=");
}

#[test]
#[cfg(feature = "non-pdk")]
fn test_rex_url_from_url_roundtrip() {
    use url::Url;

    // Plain URL roundtrip
    let original_plain = "https://api.example.com/endpoint";
    let url = Url::parse(original_plain).unwrap();
    let rex_url: RexUrl = url.into();
    assert_eq!(rex_url.to_string(), original_plain);

    // Encrypted URL roundtrip
    let original_encrypted = "enc://dGhpcyBpcyBhIHRlc3Q=";
    let url = Url::parse(original_encrypted).unwrap();
    let rex_url: RexUrl = url.into();
    assert_eq!(rex_url.to_string(), original_encrypted);
}
