use edgar_rs::*;

#[test]
fn deserialize_ticker() {
    let json = r#"{"cik_str": 320193, "ticker": "AAPL", "title": "Apple Inc."}"#;
    let t: Ticker = serde_json::from_str(json).unwrap();
    assert_eq!(t.cik, 320193);
    assert_eq!(t.ticker, "AAPL");
    assert_eq!(t.title, "Apple Inc.");
}

#[test]
fn deserialize_ticker_map() {
    let json = r#"{
        "0": {"cik_str": 320193, "ticker": "AAPL", "title": "Apple Inc."},
        "1": {"cik_str": 789019, "ticker": "MSFT", "title": "MICROSOFT CORP"}
    }"#;
    let map: std::collections::HashMap<String, Ticker> = serde_json::from_str(json).unwrap();
    assert_eq!(map.len(), 2);
    assert_eq!(map["0"].ticker, "AAPL");
    assert_eq!(map["1"].ticker, "MSFT");
}

#[test]
fn deserialize_address_with_nulls() {
    let json = r#"{
        "street1": "ONE APPLE PARK WAY",
        "street2": null,
        "city": "CUPERTINO",
        "stateOrCountry": "CA",
        "zipCode": "95014",
        "stateOrCountryDescription": "CA"
    }"#;
    let addr: Address = serde_json::from_str(json).unwrap();
    assert_eq!(addr.street1.as_deref(), Some("ONE APPLE PARK WAY"));
    assert!(addr.street2.is_none());
    assert_eq!(addr.city.as_deref(), Some("CUPERTINO"));
}

#[test]
fn deserialize_address_all_null() {
    let json = r#"{
        "street1": null,
        "street2": null,
        "city": null,
        "stateOrCountry": null,
        "zipCode": null,
        "stateOrCountryDescription": null
    }"#;
    let addr: Address = serde_json::from_str(json).unwrap();
    assert!(addr.street1.is_none());
    assert!(addr.city.is_none());
}

#[test]
fn deserialize_former_name() {
    let json = r#"{"name": "OLD NAME INC", "from": "2000-01-01", "to": "2010-06-30"}"#;
    let f: FormerName = serde_json::from_str(json).unwrap();
    assert_eq!(f.name, "OLD NAME INC");
    assert_eq!(f.from, "2000-01-01");
    assert_eq!(f.to, "2010-06-30");
}

#[test]
fn deserialize_filing_file() {
    let json = r#"{
        "name": "CIK0000320193-submissions-001.json",
        "filingCount": 40,
        "filingFrom": "2020-01-01",
        "filingTo": "2023-12-31"
    }"#;
    let f: FilingFile = serde_json::from_str(json).unwrap();
    assert_eq!(f.name, "CIK0000320193-submissions-001.json");
    assert_eq!(f.filing_count, 40);
}

#[test]
fn deserialize_filing_set() {
    let json = r#"{
        "accessionNumber": ["0000320193-24-000123"],
        "filingDate": ["2024-01-15"],
        "reportDate": ["2024-01-15"],
        "acceptanceDateTime": ["2024-01-15T16:30:00.000Z"],
        "act": ["34"],
        "form": ["10-K"],
        "fileNumber": ["001-36743"],
        "filmNumber": [""],
        "items": [""],
        "size": [12345678],
        "isXBRL": [1],
        "isInlineXBRL": [1],
        "primaryDocument": ["aapl-20240101.htm"],
        "primaryDocDescription": ["10-K"]
    }"#;
    let fs: FilingSet = serde_json::from_str(json).unwrap();
    assert_eq!(fs.accession_number.len(), 1);
    assert_eq!(fs.accession_number[0], "0000320193-24-000123");
    assert_eq!(fs.form[0], "10-K");
    assert_eq!(fs.size[0], 12345678);
    assert_eq!(fs.is_xbrl[0], 1);
    assert_eq!(fs.is_inline_xbrl[0], 1);
}

#[test]
fn deserialize_fact_with_optional_fields() {
    let json = r#"{
        "start": "2023-01-01",
        "end": "2023-12-31",
        "val": 394328000000.0,
        "accn": "0000320193-24-000123",
        "fy": 2023,
        "fp": "FY",
        "form": "10-K",
        "filed": "2024-01-15",
        "frame": "CY2023"
    }"#;
    let f: Fact = serde_json::from_str(json).unwrap();
    assert_eq!(f.start.as_deref(), Some("2023-01-01"));
    assert_eq!(f.end, "2023-12-31");
    assert_eq!(f.val, 394328000000.0);
    assert_eq!(f.fy, Some(2023));
    assert_eq!(f.fp, "FY");
    assert_eq!(f.frame.as_deref(), Some("CY2023"));
}

#[test]
fn deserialize_fact_without_optional_fields() {
    let json = r#"{
        "end": "2023-12-31",
        "val": 100.0,
        "accn": "0000320193-24-000123",
        "fy": 2023,
        "fp": "Q1",
        "form": "10-Q",
        "filed": "2024-04-15"
    }"#;
    let f: Fact = serde_json::from_str(json).unwrap();
    assert!(f.start.is_none());
    assert!(f.frame.is_none());
    assert_eq!(f.fp, "Q1");
}

#[test]
fn deserialize_fact_with_null_fy() {
    let json = r#"{
        "end": "2023-12-31",
        "val": 100.0,
        "accn": "0000320193-24-000123",
        "fy": null,
        "fp": "Q1",
        "form": "10-Q",
        "filed": "2024-04-15"
    }"#;
    let f: Fact = serde_json::from_str(json).unwrap();
    assert!(f.fy.is_none());
}

#[test]
fn deserialize_fact_with_missing_fy() {
    let json = r#"{
        "end": "2023-12-31",
        "val": 100.0,
        "accn": "0000320193-24-000123",
        "fp": "Q1",
        "form": "10-Q",
        "filed": "2024-04-15"
    }"#;
    let f: Fact = serde_json::from_str(json).unwrap();
    assert!(f.fy.is_none());
}

#[test]
fn deserialize_company_concept() {
    let json = r#"{
        "cik": 320193,
        "taxonomy": "us-gaap",
        "tag": "Revenues",
        "label": "Revenues",
        "description": "Total revenues",
        "entityName": "Apple Inc.",
        "units": {
            "USD": [
                {
                    "start": "2023-01-01",
                    "end": "2023-12-31",
                    "val": 394328000000.0,
                    "accn": "0000320193-24-000123",
                    "fy": 2023,
                    "fp": "FY",
                    "form": "10-K",
                    "filed": "2024-01-15",
                    "frame": "CY2023"
                }
            ]
        }
    }"#;
    let cc: CompanyConcept = serde_json::from_str(json).unwrap();
    assert_eq!(cc.cik, 320193);
    assert_eq!(cc.taxonomy, "us-gaap");
    assert_eq!(cc.tag, "Revenues");
    assert_eq!(cc.entity_name, "Apple Inc.");
    let usd_facts = &cc.units["USD"];
    assert_eq!(usd_facts.len(), 1);
    assert_eq!(usd_facts[0].val, 394328000000.0);
}

#[test]
fn deserialize_company_facts() {
    let json = r#"{
        "cik": 320193,
        "entityName": "Apple Inc.",
        "facts": {
            "us-gaap": {
                "Revenues": {
                    "label": "Revenues",
                    "description": "Total revenues",
                    "units": {
                        "USD": [
                            {
                                "end": "2023-12-31",
                                "val": 394328000000.0,
                                "accn": "0000320193-24-000123",
                                "fy": 2023,
                                "fp": "FY",
                                "form": "10-K",
                                "filed": "2024-01-15"
                            }
                        ]
                    }
                }
            }
        }
    }"#;
    let cf: CompanyFacts = serde_json::from_str(json).unwrap();
    assert_eq!(cf.cik, 320193);
    assert_eq!(cf.entity_name, "Apple Inc.");
    let revenues = &cf.facts["us-gaap"]["Revenues"];
    assert_eq!(revenues.label, "Revenues");
    assert_eq!(revenues.units["USD"].len(), 1);
}

#[test]
fn deserialize_frame() {
    let json = r#"{
        "taxonomy": "us-gaap",
        "tag": "Revenues",
        "ccp": "CY2023",
        "uom": "USD",
        "label": "Revenues",
        "description": "Total revenues",
        "pts": 2,
        "data": [
            {
                "accn": "0000320193-24-000123",
                "cik": 320193,
                "entityName": "Apple Inc.",
                "loc": "US-CA",
                "start": "2023-01-01",
                "end": "2023-12-31",
                "val": 394328000000.0
            },
            {
                "accn": "0000789019-24-000456",
                "cik": 789019,
                "entityName": "MICROSOFT CORP",
                "loc": "US-WA",
                "end": "2023-12-31",
                "val": 211915000000.0
            }
        ]
    }"#;
    let f: Frame = serde_json::from_str(json).unwrap();
    assert_eq!(f.taxonomy, "us-gaap");
    assert_eq!(f.ccp, "CY2023");
    assert_eq!(f.pts, 2);
    assert_eq!(f.data.len(), 2);
    assert_eq!(f.data[0].entity_name, "Apple Inc.");
    assert_eq!(f.data[0].start.as_deref(), Some("2023-01-01"));
    assert!(f.data[1].start.is_none());
}

#[test]
fn deserialize_frame_data_without_start() {
    let json = r#"{
        "accn": "0000789019-24-000456",
        "cik": 789019,
        "entityName": "MICROSOFT CORP",
        "loc": "US-WA",
        "end": "2023-12-31",
        "val": 211915000000.0
    }"#;
    let fd: FrameData = serde_json::from_str(json).unwrap();
    assert!(fd.start.is_none());
    assert_eq!(fd.cik, 789019);
}

#[test]
fn search_options_default() {
    let opts = SearchOptions::default();
    assert!(opts.forms.is_empty());
    assert!(opts.date_start.is_none());
    assert!(opts.date_end.is_none());
    assert!(opts.from.is_none());
}

#[test]
fn serialize_and_deserialize_ticker_roundtrip() {
    let json = r#"{"cik_str":320193,"ticker":"AAPL","title":"Apple Inc."}"#;
    let t: Ticker = serde_json::from_str(json).unwrap();
    let back = serde_json::to_string(&t).unwrap();
    let t2: Ticker = serde_json::from_str(&back).unwrap();
    assert_eq!(t.cik, t2.cik);
    assert_eq!(t.ticker, t2.ticker);
}

#[test]
fn deserialize_submission_minimal() {
    let json = r#"{
        "cik": "320193",
        "entityType": "operating",
        "sic": "3571",
        "sicDescription": "ELECTRONIC COMPUTERS",
        "insiderTransactionForOwnerExists": 1,
        "insiderTransactionForIssuerExists": 1,
        "name": "Apple Inc.",
        "tickers": ["AAPL"],
        "exchanges": ["Nasdaq"],
        "ein": "942404110",
        "description": "",
        "website": "https://www.apple.com",
        "investorWebsite": "",
        "category": "Large accelerated filer",
        "fiscalYearEnd": "0930",
        "stateOfIncorporation": "CA",
        "stateOfIncorporationDescription": "CA",
        "addresses": {
            "mailing": {
                "street1": "ONE APPLE PARK WAY",
                "street2": null,
                "city": "CUPERTINO",
                "stateOrCountry": "CA",
                "zipCode": "95014",
                "stateOrCountryDescription": "CA"
            },
            "business": {
                "street1": "ONE APPLE PARK WAY",
                "street2": null,
                "city": "CUPERTINO",
                "stateOrCountry": "CA",
                "zipCode": "95014",
                "stateOrCountryDescription": "CA"
            }
        },
        "phone": "408-996-1010",
        "flags": "",
        "formerNames": [],
        "filings": {
            "recent": {
                "accessionNumber": [],
                "filingDate": [],
                "reportDate": [],
                "acceptanceDateTime": [],
                "act": [],
                "form": [],
                "fileNumber": [],
                "filmNumber": [],
                "items": [],
                "size": [],
                "isXBRL": [],
                "isInlineXBRL": [],
                "primaryDocument": [],
                "primaryDocDescription": []
            },
            "files": []
        }
    }"#;
    let sub: Submission = serde_json::from_str(json).unwrap();
    assert_eq!(sub.cik, "320193");
    assert_eq!(sub.name, "Apple Inc.");
    assert_eq!(sub.sic, "3571");
    assert_eq!(sub.sic_description, "ELECTRONIC COMPUTERS");
    assert_eq!(sub.tickers, vec!["AAPL"]);
    assert_eq!(sub.exchanges, vec!["Nasdaq"]);
    assert_eq!(
        sub.addresses.mailing.street1.as_deref(),
        Some("ONE APPLE PARK WAY")
    );
    assert!(sub.addresses.mailing.street2.is_none());
    assert!(sub.former_names.is_empty());
    assert!(sub.filings.files.is_empty());
}

#[test]
fn deserialize_concept_facts() {
    let json = r#"{
        "label": "Assets",
        "description": "Total assets",
        "units": {
            "USD": [
                {
                    "end": "2023-12-31",
                    "val": 352583000000.0,
                    "accn": "0000320193-24-000123",
                    "fy": 2023,
                    "fp": "FY",
                    "form": "10-K",
                    "filed": "2024-01-15"
                }
            ]
        }
    }"#;
    let cf: ConceptFacts = serde_json::from_str(json).unwrap();
    assert_eq!(cf.label, "Assets");
    assert_eq!(cf.units["USD"][0].val, 352583000000.0);
}
