//   Copyright 2025 The Tari Project
//   SPDX-License-Identifier: BSD-3-Clause

use tari_ootle_transaction::{Transaction, args};
use tari_template_lib::types::{Amount, ComponentAddress};
use tari_template_test_tooling::{TemplateTest, support::confidential::generate_confidential_output_statement};

const CRATE_PATH: &str = env!("CARGO_MANIFEST_DIR");

#[test]
fn it_burns_all_resource_types() {
    let mut test = TemplateTest::new(CRATE_PATH, ["tests/templates/burn"]);
    let recall_template = test.get_template_address("Burn");

    let (mut initial_supply, _mask, _) = generate_confidential_output_statement(1000, None);
    initial_supply.output_revealed_amount = Amount::from(1000u64);

    let result = test.execute_expect_success(
        Transaction::builder_localnet()
            .call_function(recall_template, "new", args![initial_supply])
            .build_and_seal(test.secret_key()),
        vec![],
    );

    let component: ComponentAddress = result.finalize.execution_results[0].decode().unwrap();

    // Burn fields: 0=fungible, 1=non_fungible, 2=confidential, 3=stealth.
    let fungible_vault = test.extract_component_value(component, "$.0");
    let non_fungible_vault = test.extract_component_value(component, "$.1");
    let confidential_vault = test.extract_component_value(component, "$.2");
    let stealth_vault = test.extract_component_value(component, "$.3");

    {
        let store = test.read_only_state_store();
        let fungible_resource = *store.get_vault(&fungible_vault).unwrap().resource_address();
        let resource = store.get_resource(&fungible_resource).unwrap();
        assert_eq!(resource.total_supply(), Some(Amount::from(1_000_000u64)));

        let non_fungible_resource = *store.get_vault(&non_fungible_vault).unwrap().resource_address();
        let resource = store.get_resource(&non_fungible_resource).unwrap();
        assert_eq!(resource.total_supply(), Some(Amount::from(10u64)));

        let confidential_resource = *store.get_vault(&confidential_vault).unwrap().resource_address();
        let resource = store.get_resource(&confidential_resource).unwrap();
        assert_eq!(resource.total_supply(), Some(Amount::from(1000u64)));

        let stealth_resource = *store.get_vault(&stealth_vault).unwrap().resource_address();
        let resource = store.get_resource(&stealth_resource).unwrap();
        assert_eq!(resource.total_supply(), Some(Amount::from(1_000_000u64)));
    }

    test.execute_expect_success(
        Transaction::builder_localnet()
            .call_method(component, "burn_all", args![])
            .build_and_seal(test.secret_key()),
        vec![],
    );

    let vault = test.read_only_state_store().get_vault(&fungible_vault).unwrap();
    assert_eq!(vault.balance(), 0);

    let vault = test.read_only_state_store().get_vault(&non_fungible_vault).unwrap();
    assert_eq!(vault.balance(), 0);

    let vault = test.read_only_state_store().get_vault(&confidential_vault).unwrap();
    assert_eq!(vault.balance(), 0);

    let vault = test.read_only_state_store().get_vault(&stealth_vault).unwrap();
    assert_eq!(vault.balance(), 0);

    {
        let store = test.read_only_state_store();
        let fungible_resource = *store.get_vault(&fungible_vault).unwrap().resource_address();
        let resource = store.get_resource(&fungible_resource).unwrap();
        assert_eq!(resource.total_supply(), Some(Amount::ZERO));

        let non_fungible_resource = *store.get_vault(&non_fungible_vault).unwrap().resource_address();
        let resource = store.get_resource(&non_fungible_resource).unwrap();
        assert_eq!(resource.total_supply(), Some(Amount::ZERO));

        let confidential_resource = *store.get_vault(&confidential_vault).unwrap().resource_address();
        let resource = store.get_resource(&confidential_resource).unwrap();
        assert_eq!(resource.total_supply(), Some(Amount::ZERO));

        let stealth_resource = *store.get_vault(&stealth_vault).unwrap().resource_address();
        let resource = store.get_resource(&stealth_resource).unwrap();
        assert_eq!(resource.total_supply(), Some(Amount::ZERO));
    }
}
