# Copyright 2021 DFINITY Stiftung

# Licensed under the Apache License, Version 2.0 (the "License"); you may not use
# this file except in compliance with the License. You may obtain a copy of the
# License at

#    http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.

# The original license for the DFINITY code can be found here: https://github.com/dfinity/ic/blob/master/LICENSE
# This file contains derivative works licensed as MIT: https://github.com/demergent-labs/azle/blob/main/LICENSE

# Taken in part from: https://github.com/dfinity/interface-spec/blob/master/spec/ic.did

from basilisk import blob, Principal, Service, service_update, Vec, void

# The as expressions are reexporting these variables
from basilisk.canisters.management.basic import (
    CanisterSettings as CanisterSettings,
    CanisterStatus as CanisterStatus,
    CanisterStatusArgs as CanisterStatusArgs,
    CanisterStatusResult as CanisterStatusResult,
    CreateCanisterArgs as CreateCanisterArgs,
    CreateCanisterResult as CreateCanisterResult,
    DefiniteCanisterSettings as DefiniteCanisterSettings,
    DeleteCanisterArgs as DeleteCanisterArgs,
    DepositCyclesArgs as DepositCyclesArgs,
    InstallCodeArgs as InstallCodeArgs,
    InstallCodeMode as InstallCodeMode,
    ProvisionalCreateCanisterWithCyclesArgs as ProvisionalCreateCanisterWithCyclesArgs,
    ProvisionalCreateCanisterWithCyclesResult as ProvisionalCreateCanisterWithCyclesResult,
    ProvisionalTopUpCanisterArgs as ProvisionalTopUpCanisterArgs,
    StartCanisterArgs as StartCanisterArgs,
    StopCanisterArgs as StopCanisterArgs,
    UninstallCodeArgs as UninstallCodeArgs,
    UpdateSettingsArgs as UpdateSettingsArgs,
    # Chunked code upload API
    ChunkHash as ChunkHash,
    UploadChunkArgs as UploadChunkArgs,
    UploadChunkResult as UploadChunkResult,
    ClearChunkStoreArgs as ClearChunkStoreArgs,
    StoredChunksArgs as StoredChunksArgs,
    StoredChunksResult as StoredChunksResult,
    InstallChunkedCodeArgs as InstallChunkedCodeArgs,
)
from basilisk.canisters.management.tecdsa import (
    EcdsaCurve as EcdsaCurve,
    EcdsaPublicKeyArgs as EcdsaPublicKeyArgs,
    EcdsaPublicKeyResult as EcdsaPublicKeyResult,
    KeyId as KeyId,
    SignWithEcdsaArgs as SignWithEcdsaArgs,
    SignWithEcdsaResult as SignWithEcdsaResult,
)
from basilisk.canisters.management.http import (
    HttpHeader as HttpHeader,
    HttpMethod as HttpMethod,
    HttpRequestArgs as HttpRequestArgs,
    HttpResponse as HttpResponse,
    HttpTransform as HttpTransform,
    HttpTransformArgs as HttpTransformArgs,
    HttpTransformFunc as HttpTransformFunc,
)
from basilisk.canisters.management.bitcoin import (
    BitcoinAddress as BitcoinAddress,
    BitcoinNetwork as BitcoinNetwork,
    BlockHash as BlockHash,
    GetBalanceArgs as GetBalanceArgs,
    GetCurrentFeePercentilesArgs as GetCurrentFeePercentilesArgs,
    GetUtxosArgs as GetUtxosArgs,
    GetUtxosResult as GetUtxosResult,
    Page as Page,
    MillisatoshiPerByte as MillisatoshiPerByte,
    Outpoint as Outpoint,
    Satoshi as Satoshi,
    SendTransactionArgs as SendTransactionArgs,
    SendTransactionError as SendTransactionError,
    Utxo as Utxo,
    UtxosFilter as UtxosFilter,
)

# TODO change the return types to void


class ManagementCanister(Service):
    @service_update
    def bitcoin_get_balance(self, args: GetBalanceArgs) -> Satoshi:
        ...

    @service_update
    def bitcoin_get_current_fee_percentiles(
        self, args: GetCurrentFeePercentilesArgs
    ) -> Vec[MillisatoshiPerByte]:
        ...

    @service_update
    def bitcoin_get_utxos(self, args: GetUtxosArgs) -> GetUtxosResult:
        ...

    @service_update
    def bitcoin_send_transaction(self, args: SendTransactionArgs) -> void:
        ...

    @service_update
    def create_canister(self, args: CreateCanisterArgs) -> CreateCanisterResult:
        ...

    @service_update
    def update_settings(self, args: UpdateSettingsArgs) -> void:
        ...

    @service_update
    def install_code(self, args: InstallCodeArgs) -> void:
        ...

    @service_update
    def uninstall_code(self, args: UninstallCodeArgs) -> void:
        ...

    @service_update
    def start_canister(self, args: StartCanisterArgs) -> void:
        ...

    @service_update
    def stop_canister(self, args: StopCanisterArgs) -> void:
        ...

    @service_update
    def canister_status(self, args: CanisterStatusArgs) -> CanisterStatusResult:
        ...

    @service_update
    def delete_canister(self, args: DeleteCanisterArgs) -> void:
        ...

    @service_update
    def deposit_cycles(self, args: DepositCyclesArgs) -> void:
        ...

    @service_update
    def raw_rand(self) -> blob:
        ...

    @service_update
    def provisional_create_canister_with_cycles(
        self, args: ProvisionalCreateCanisterWithCyclesArgs
    ) -> ProvisionalCreateCanisterWithCyclesResult:
        ...

    @service_update
    def provisional_top_up_canister(self, args: ProvisionalTopUpCanisterArgs) -> void:
        ...

    @service_update
    def http_request(self, args: HttpRequestArgs) -> HttpResponse:
        ...

    @service_update
    def ecdsa_public_key(self, args: EcdsaPublicKeyArgs) -> EcdsaPublicKeyResult:
        ...

    @service_update
    def sign_with_ecdsa(self, args: SignWithEcdsaArgs) -> SignWithEcdsaResult:
        ...

    # Chunked code upload API (for WASMs > 10MB)
    @service_update
    def upload_chunk(self, args: UploadChunkArgs) -> UploadChunkResult:
        ...

    @service_update
    def clear_chunk_store(self, args: ClearChunkStoreArgs) -> void:
        ...

    @service_update
    def stored_chunks(self, args: StoredChunksArgs) -> Vec[StoredChunksResult]:
        ...

    @service_update
    def install_chunked_code(self, args: InstallChunkedCodeArgs) -> void:
        ...


management_canister = ManagementCanister(Principal.from_str("aaaaa-aa"))

setattr(ManagementCanister, '_arg_types', {
    'create_canister': 'record { settings : opt record { controllers : opt vec principal; compute_allocation : opt nat; memory_allocation : opt nat; freezing_threshold : opt nat } }',
    'update_settings': 'record { canister_id : principal; settings : record { controllers : opt vec principal; compute_allocation : opt nat; memory_allocation : opt nat; freezing_threshold : opt nat } }',
    'install_code': 'record { mode : variant { install : null; reinstall : null; upgrade : null }; canister_id : principal; wasm_module : blob; arg : blob }',
    'uninstall_code': 'record { canister_id : principal }',
    'start_canister': 'record { canister_id : principal }',
    'stop_canister': 'record { canister_id : principal }',
    'canister_status': 'record { canister_id : principal }',
    'delete_canister': 'record { canister_id : principal }',
    'deposit_cycles': 'record { canister_id : principal }',
    'provisional_create_canister_with_cycles': 'record { amount : opt nat; settings : opt record { controllers : opt vec principal; compute_allocation : opt nat; memory_allocation : opt nat; freezing_threshold : opt nat } }',
    'provisional_top_up_canister': 'record { canister_id : principal; amount : nat }',
    'http_request': 'record { url : text; max_response_bytes : opt nat64; method : variant { get : null; head : null; post : null }; headers : vec record { name : text; value : text }; body : opt blob; transform : opt record { function : func (record { response : record { status : nat; headers : vec record { name : text; value : text }; body : blob }; context : blob }) -> (record { status : nat; headers : vec record { name : text; value : text }; body : blob }) query; context : blob } }',
    'ecdsa_public_key': 'record { canister_id : opt principal; derivation_path : vec blob; key_id : record { curve : variant { secp256k1 : null }; name : text } }',
    'sign_with_ecdsa': 'record { message_hash : blob; derivation_path : vec blob; key_id : record { curve : variant { secp256k1 : null }; name : text } }',
    'bitcoin_get_balance': 'record { address : text; min_confirmations : opt nat32; network : variant { Mainnet : null; Testnet : null; Regtest : null } }',
    'bitcoin_get_utxos': 'record { address : text; filter : opt variant { min_confirmations : nat32; page : blob }; network : variant { Mainnet : null; Testnet : null; Regtest : null } }',
    'bitcoin_get_current_fee_percentiles': 'record { network : variant { Mainnet : null; Testnet : null; Regtest : null } }',
    'bitcoin_send_transaction': 'record { transaction : blob; network : variant { Mainnet : null; Testnet : null; Regtest : null } }',
})
setattr(ManagementCanister, '_return_types', {
    'create_canister': 'record { canister_id : principal }',
    'canister_status': 'record { status : variant { running : null; stopping : null; stopped : null }; settings : record { controllers : vec principal; compute_allocation : nat; memory_allocation : nat; freezing_threshold : nat }; module_hash : opt blob; memory_size : nat; cycles : nat }',
    'raw_rand': 'blob',
    'http_request': 'record { status : nat; headers : vec record { name : text; value : text }; body : blob }',
    'ecdsa_public_key': 'record { public_key : blob; chain_code : blob }',
    'sign_with_ecdsa': 'record { signature : blob }',
    'bitcoin_get_balance': 'nat64',
    'bitcoin_get_utxos': 'record { next_page : opt blob; tip_block_hash : blob; tip_height : nat32; utxos : vec record { height : nat32; outpoint : record { txid : blob; vout : nat32 }; value : nat64 } }',
    'bitcoin_get_current_fee_percentiles': 'vec nat64',
})
