use std::collections::HashMap;

use wicked_waifus_protocol::{CommonTagData, EntityCommonTagNotify, EntityStateReadyNotify, ItemRewardNotify, NormalItemUpdateNotify, RewardItemInfo, WR};

use wicked_waifus_data::pb_components::action::{Action, ChangeSelfEntityState, UnlockTeleportTrigger};
use wicked_waifus_data::pb_components::entity_state::EntityStateComponent;

use crate::logic::ecs::component::ComponentContainer;
use crate::logic::player::ItemUsage;
use crate::logic::thread_mgr::NetContext;
use crate::logic::utils::tag_utils;
use crate::query_components;

macro_rules! unimplemented_action {
    ($action:ident) => {
        {
            tracing::warn!("Action not implemented for: {:?}", $action);
        }
    }
}

pub fn perform_action(ctx: &mut NetContext,
                      entity_id: i64,
                      level_entity_data: &wicked_waifus_data::level_entity_config_data::LevelEntityConfigData,
                      template_config: &wicked_waifus_data::template_config_data::TemplateConfigData,
                      element: Action) {
    match element {
        Action::SetBattleState(action) => unimplemented_action! { action },
        Action::ExecBattleAction(action) => unimplemented_action! { action },
        Action::WaitBattleCondition(action) => unimplemented_action! { action },
        Action::PlayFlow(action) => unimplemented_action! { action },
        Action::Collect(_) => collect_action(ctx, level_entity_data, template_config),
        Action::LeisureInteract(action) => unimplemented_action! { action },
        Action::UnlockTeleportTrigger(action) => unlock_teleport_trigger(ctx, action.params),
        Action::EnableTemporaryTeleport(action) => unimplemented_action! { action },
        Action::OpenSystemBoard(action) => unimplemented_action! { action },
        Action::OpenSystemFunction(action) => unimplemented_action! { action },
        Action::ChangeSelfEntityState(action) => change_self_entity_state(ctx, entity_id, level_entity_data, template_config, action.params),
        Action::SetPlayerOperationRestriction(action) => unimplemented_action! { action },
        Action::Wait(action) => unimplemented_action! { action },
        Action::ChangeEntityState(action) => unimplemented_action! { action },
        Action::Log(action) => unimplemented_action! { action },
        Action::EnableNearbyTracking(action) => unimplemented_action! { action },
        Action::TeleportDungeon(action) => unimplemented_action! { action },
        Action::DestroySelf(action) => unimplemented_action! { action },
        Action::CameraLookAt(action) => unimplemented_action! { action },
        Action::StopCameraLookAt(action) => unimplemented_action! { action },
        Action::EnterOrbitalCamera(action) => unimplemented_action! { action },
        Action::ExitOrbitalCamera(action) => unimplemented_action! { action },
        Action::SendAiEvent(action) => unimplemented_action! { action },
        Action::SetInteractionLockState(action) => unimplemented_action! { action },
        Action::AwakeEntity(action) => unimplemented_action! { action },
        Action::ChangeLiftTarget(action) => unimplemented_action! { action },
        Action::CalculateVar(action) => unimplemented_action! { action },
        Action::AddBuffToPlayer(action) => unimplemented_action! { action },
        Action::RemoveBuffFromPlayer(action) => unimplemented_action! { action },
        Action::AddBuffToEntity(action) => unimplemented_action! { action },
        Action::RemoveBuffFromEntity(action) => unimplemented_action! { action },
        Action::Prompt(action) => unimplemented_action! { action },
        Action::SetEntityVisible(action) => unimplemented_action! { action },
        Action::DestroyEntity(action) => unimplemented_action! { action },
        Action::GuideTrigger(action) => unimplemented_action! { action },
        Action::TriggerCameraShake(action) => unimplemented_action! { action },
        Action::SetVar(action) => unimplemented_action! { action },
        Action::VehicleEnter(action) => unimplemented_action! { action },
        Action::VehicleExitPlayer(action) => unimplemented_action! { action },
        Action::LockEntity(action) => unimplemented_action! { action },
        Action::UnlockEntity(action) => unimplemented_action! { action },
        Action::CommonTip(action) => unimplemented_action! { action },
        Action::CommonTip2(action) => unimplemented_action! { action },
        Action::PostAkEvent(action) => unimplemented_action! { action },
        Action::VehicleEnterNpc(action) => unimplemented_action! { action },
        Action::VehicleExitNpc(action) => unimplemented_action! { action },
        Action::PlayerLookAt(action) => unimplemented_action! { action },
        Action::PlayBubble(action) => unimplemented_action! { action },
        Action::AddPlayBubble(action) => unimplemented_action! { action },
        Action::ClearPlayBubble(action) => unimplemented_action! { action },
        Action::ExecRiskHarvestEffect(action) => unimplemented_action! { action },
        Action::EnableLevelPlay(action) => unimplemented_action! { action },
        Action::ClaimLevelPlayReward(action) => unimplemented_action! { action },
        Action::SettlementDungeon(action) => unimplemented_action! { action },
        Action::ExitDungeon(action) => unimplemented_action! { action },
        Action::FinishDungeon(action) => unimplemented_action! { action },
        Action::RecordDungeonEvent(action) => unimplemented_action! { action },
        Action::RecoverDurability(action) => unimplemented_action! { action },
        Action::FadeInScreen(action) => unimplemented_action! { action },
        Action::FadeOutScreen(action) => unimplemented_action! { action },
        Action::ChangeNpcPerformState(action) => unimplemented_action! { action },
        Action::EntityTurnTo(action) => unimplemented_action! { action },
        Action::EntityLookAt(action) => unimplemented_action! { action },
        Action::ToggleMapMarkState(action) => unimplemented_action! { action },
        Action::RandomVar(action) => unimplemented_action! { action },
        Action::ModifySceneItemAttributeTag(action) => unimplemented_action! { action },
        Action::VehicleWaterfallClimbing(action) => unimplemented_action! { action },
        Action::VehicleTeleport(action) => unimplemented_action! { action },
        Action::RogueGotoNextFloor(action) => unimplemented_action! { action },
        Action::RogueReceiveReward(action) => unimplemented_action! { action },
        Action::RogueSelectRoom(action) => unimplemented_action! { action },
        Action::RogueActivatePortal(action) => unimplemented_action! { action },
        Action::MowingTowerGotoNextFloor(action) => unimplemented_action! { action },
        Action::SlashAndTowerGotoNextFloor(action) => unimplemented_action! { action },
        Action::PlayMontage(action) => unimplemented_action! { action },
        Action::OpenSystemBoardWithReturn(action) => unimplemented_action! { action },
        Action::UnlockSystemItem(action) => unimplemented_action! { action },
        Action::SetSportsState(action) => unimplemented_action! { action },
        Action::OpenSimpleGameplay(action) => unimplemented_action! { action },
        Action::PlayEffect(action) => unimplemented_action! { action },
        Action::PlayEffect2(action) => unimplemented_action! { action },
        Action::RestorePlayerCameraAdjustment(action) => unimplemented_action! { action },
        Action::AdjustPlayerCamera(action) => unimplemented_action! { action },
        Action::SetPlayerPos(action) => unimplemented_action! { action },
        Action::MoveWithSpline(action) => unimplemented_action! { action },
        Action::EnableSplineMoveModel(action) => unimplemented_action! { action },
        Action::ToggleScanSplineEffect(action) => unimplemented_action! { action },
        Action::MoveSceneItem(action) => unimplemented_action! { action },
        Action::StopSceneItemMove(action) => unimplemented_action! { action },
        Action::FireBullet(action) => unimplemented_action! { action },
        Action::ClearFishingCabinInSaleItems(action) => unimplemented_action! { action },
        Action::AcceptFishingEntrust(action) => unimplemented_action! { action },
        Action::DestroyFishingBoat(action) => unimplemented_action! { action },
        Action::SetJigsawItem(action) => unimplemented_action! { action },
        Action::SetJigsawFoundation(action) => unimplemented_action! { action },
        Action::SetTeleControl(action) => unimplemented_action! { action },
        Action::SetEntityClientVisible(action) => unimplemented_action! { action },
        Action::ToggleHighlightExploreUi(action) => unimplemented_action! { action },
        Action::ExecAlertSystemAction(action) => unimplemented_action! { action },
        Action::AddFlowInteractOption(action) => unimplemented_action! { action },
        Action::RemoveFlowInteractOption(action) => unimplemented_action! { action },
        Action::EnableHostility(action) => unimplemented_action! { action },
        Action::ChangePhantomFormation(action) => unimplemented_action! { action },
        Action::RestorePhantomFormation(action) => unimplemented_action! { action },
        Action::ChangeTimer(action) => unimplemented_action! { action },
        Action::ToggleTimerPauseState(action) => unimplemented_action! { action },
        Action::ChangeFightTeam(action) => unimplemented_action! { action },
        Action::AddTrialFollowShooter(action) => unimplemented_action! { action },
        Action::RemoveTrialFollowShooter(action) => unimplemented_action! { action },
        Action::AddTrialCharacter(action) => unimplemented_action! { action },
        Action::RemoveTrialCharacter(action) => unimplemented_action! { action },
        Action::UpdateTrialCharacter(action) => unimplemented_action! { action },
        Action::RestoreTrialCharacter(action) => unimplemented_action! { action },
        Action::SetAreaState(action) => unimplemented_action! { action },
        Action::SwitchSubLevels(action) => unimplemented_action! { action },
        Action::ChangeTeamPosition(action) => unimplemented_action! { action },
        Action::GetItem(action) => unimplemented_action! { action },
        Action::CreatePrefab(action) => unimplemented_action! { action },
        Action::DestroyPrefab(action) => unimplemented_action! { action },
        Action::CompleteGuide(action) => unimplemented_action! { action },
        Action::PlayDynamicSettlement(action) => unimplemented_action! { action },
        Action::UsePhantomSkill(action) => unimplemented_action! { action },
        Action::HideTargetRange(action) => unimplemented_action! { action },
        Action::ChangeOtherState(action) => unimplemented_action! { action },
        Action::SetRegionConfig(action) => unimplemented_action! { action },
        Action::SetReviveRegion(action) => unimplemented_action! { action },
        Action::ExecResurrection(action) => unimplemented_action! { action },
        Action::ShowTargetRange(action) => unimplemented_action! { action },
        Action::SetTime(action) => unimplemented_action! { action },
        Action::SetTimeLockState(action) => unimplemented_action! { action },
        Action::EnableSystem(action) => unimplemented_action! { action },
        Action::EnableAoiNotify(action) => unimplemented_action! { action },
        Action::SetForceLock(action) => unimplemented_action! { action },
        Action::PlayRegisteredMontage(action) => unimplemented_action! { action },
        Action::SetAudioState(action) => unimplemented_action! { action },
        Action::HideGroup(action) => unimplemented_action! { action },
        Action::ShowHidedGroup(action) => unimplemented_action! { action },
        Action::HideSpecificEntities(action) => unimplemented_action! { action },
        Action::ShowSpecificEntities(action) => unimplemented_action! { action },
        Action::RemovePreloadResource(action) => unimplemented_action! { action },
        Action::Preload(action) => unimplemented_action! { action },
        Action::EnableAI(action) => unimplemented_action! { action },
        Action::SwitchDataLayers(action) => unimplemented_action! { action },
        Action::DestroyQuest(action) => unimplemented_action! { action },
        Action::DestroyQuestItem(action) => unimplemented_action! { action },
        Action::PromptQuestChapterUI(action) => unimplemented_action! { action },
        Action::TakePlotPhoto(action) => unimplemented_action! { action },
        Action::SetWuYinQuState(action) => unimplemented_action! { action },
        Action::RunActions(action) => unimplemented_action! { action },
        Action::ManualOccupations(action) => unimplemented_action! { action },
        Action::SetWeather(action) => unimplemented_action! { action },
        Action::SendNpcMail(action) => unimplemented_action! { action },
        Action::EnableFunction(action) => unimplemented_action! { action },
        Action::FocusOnMapMark(action) => unimplemented_action! { action },
        Action::CharacterLookAt(action) => unimplemented_action! { action },
        Action::AddGuestCharacter(action) => unimplemented_action! { action },
        Action::RemoveGuestCharacter(action) => unimplemented_action! { action },
        Action::TeleportToAndEnterVehicle(action) => unimplemented_action! { action },
        Action::SetAreaTimeState(action) => unimplemented_action! { action },
        Action::ResetPlayerCameraFocus(action) => unimplemented_action! { action },
        Action::ResetLevelPlay(action) => unimplemented_action! { action },
        Action::VehicleSprint(action) => unimplemented_action! { action },
        Action::VehicleMoveWithPathLine(action) => unimplemented_action! { action },
        Action::ClientPreEnableSubLevels(action) => unimplemented_action! { action },
        Action::GuestOperateUiAnimation(action) => unimplemented_action! { action },
        Action::ChangeEntityCamp(action) => unimplemented_action! { action },
        Action::NewMoveWithSpline(action) => unimplemented_action! { action },
        Action::DangoAbyssActivatePortal(action) => unimplemented_action! { action },
        Action::DangoAbyssCreateRewardTreasureBox(action) => unimplemented_action! { action },
        Action::DangoAbyssGotoNextFloor(action) => unimplemented_action! { action },
        Action::DangoAbyssReceiveReward(action) => unimplemented_action! { action },
        Action::SummonEntity(action) => unimplemented_action! { action },
        Action::GetRewardByInteract(action) => unimplemented_action! { action },
        Action::OpenQte(action) => unimplemented_action! { action },
        Action::ActiveAntiGravitySafePoint(action) => unimplemented_action! { action },
        Action::BvbPlayDialog(action) => unimplemented_action! { action },
        Action::BvbSendSystemEvent(action) => unimplemented_action! { action },
        Action::BvbSendAiEvent(action) => unimplemented_action! { action },
        Action::BvbPlayerOperationConstraint(action) => unimplemented_action! { action },
        Action::ExecClientBattleAction(action) => unimplemented_action! { action },
        Action::TriggerSpecificScanEffect(action) => unimplemented_action! { action },
        Action::SetActorVar(action) => unimplemented_action! { action },
        Action::RunActorCustomEvent(action) => unimplemented_action! { action },
        Action::StopUiScreenEffect(action) => unimplemented_action! { action },
        Action::StopNewMoveWithSpline(action) => unimplemented_action! { action },
        Action::RequestSystemFunction(action) => unimplemented_action! { action },
        Action::SetTimeScale(action) => unimplemented_action! { action },
        Action::EndCommonTip(action) => unimplemented_action! { action },
        Action::SetupMoraleSystem(action) => unimplemented_action! { action },
    }
}

fn collect_action(ctx: &mut NetContext,
                  level_entity_data: &wicked_waifus_data::level_entity_config_data::LevelEntityConfigData,
                  template_config: &wicked_waifus_data::template_config_data::TemplateConfigData) {
    if let Some(reward_component) = level_entity_data.components_data.reward_component
        .as_ref()
        .or(template_config.components_data.reward_component.as_ref()) {
        if reward_component.disabled.unwrap_or(false) {
            return;
        }
        // TODO: check the use of reward_type and drop_on_event
        //      Seems type 0 is reward from preview, while 1 and 2 is unknown
        if let Some(reward_id) = reward_component.reward_id {
            let drop = wicked_waifus_data::drop_package_data::get(&reward_id).unwrap();
            let usages = drop.drop_preview.iter()
                .map(|(&id, &quantity)| ItemUsage { id, quantity })
                .collect::<Vec<_>>();
            let updated_items = ctx.player.inventory.add_items(&usages);
            let normal_item_list = ctx.player.inventory.to_normal_item_list_filtered(
                &updated_items.keys().cloned().collect::<Vec<i32>>()
            );
            ctx.player.notify(NormalItemUpdateNotify { normal_item_list, no_tips: false });
            // UpdateHandBookActiveStateMapNotify
            let mut rewards: HashMap<i32, WR> = HashMap::new();
            rewards.insert(0, WR {
                item_list: drop.drop_preview.iter()
                    .map(|(&id, &quantity)| RewardItemInfo {
                        show_plan_id: 0, // TODO: Check how to get this
                        item_id: id,
                        count: quantity,
                        incr_id: 0,
                    })
                    .collect::<Vec<_>>(),
            });
            ctx.player.notify(ItemRewardNotify {
                drop_id: reward_id,
                reason: 15000,
                magnification: 1,
                reward_items: rewards,
            });
        }
        // TODO: Should we remove entity?? get pcap
    }
}

#[inline(always)]
fn unlock_teleport_trigger(ctx: &mut NetContext, action: UnlockTeleportTrigger) {
    ctx.player.unlock_teleport(action.teleport_id)
}

fn change_self_entity_state(ctx: &mut NetContext,
                            entity_id: i64,
                            level_entity_data: &wicked_waifus_data::level_entity_config_data::LevelEntityConfigData,
                            template_config: &wicked_waifus_data::template_config_data::TemplateConfigData,
                            action: ChangeSelfEntityState) {
    let state = tag_utils::get_tag_id_by_name(action.entity_state.as_str());

    // TODO: update Tag::CommonEntityTags too??
    let old_state = {
        let world = ctx.world.get_world_entity();
        let mut state_tag = query_components!(world, entity_id, StateTag).0.unwrap();
        let old_state = state_tag.state_tag_id;
        tracing::debug!("ChangeSelfEntityState: old state {old_state} -> new state: {state}");
        state_tag.state_tag_id = state;
        old_state
    };

    if let Some(entity_state_component) = level_entity_data.components_data.entity_state_component.as_ref()
        .or(template_config.components_data.entity_state_component.as_ref()).cloned() {
        let entity_state_component: EntityStateComponent = entity_state_component;  // TODO: Remove this line, used for casting only

        // TODO: implement rest of cases
        if let Some(state_change_behaviors) = entity_state_component.state_change_behaviors {
            for state_change_behavior in state_change_behaviors {
                // TODO: implement rest of cases
                let expected = tag_utils::get_tag_id_by_name(state_change_behavior.state.as_str());

                if expected == state {
                    if let Some(actions) = state_change_behavior.action {
                        for sub in actions {
                            perform_action(ctx, entity_id, level_entity_data, template_config, sub);
                        }
                    }
                }
            }
        }
    }

    ctx.player.notify(EntityCommonTagNotify {
        id: entity_id,
        tags: vec![
            CommonTagData { tag_id: old_state, remove_tag_ids: false }, // Remove
            CommonTagData { tag_id: state, remove_tag_ids: true }, // Add
        ],
    });

    ctx.player.notify(EntityStateReadyNotify {
        entity_id,
        tag_id: state,
        ready: true, // TODO: Always true? or shall we compare it to something??
    });
}