<?php
/*
|--------------------------------------------------------------------------
| ColibriPlus - The Social Network Web Application.
|--------------------------------------------------------------------------
| Author: Mansur Terla. Full-Stack Web Developer, UI/UX Designer.
| Website: www.terla.me
| E-mail: mansurtl.contact@gmail.com
| Instagram: @mansur_terla
| Telegram: @mansurtl_contact
|--------------------------------------------------------------------------
| Copyright (c)  ColibriPlus. All rights reserved.
|--------------------------------------------------------------------------
*/

namespace App\Actions\User;

use Throwable;
use App\Models\Chat;
use App\Models\Post;
use App\Models\User;
use App\Models\Report;
use App\Models\Comment;
use App\Models\Bookmark;
use App\Models\StoryView;
use App\Models\ChatInvite;
use App\Models\HiddenChat;
use App\Enums\Chat\ChatType;
use App\Models\HiddenMessage;
use App\Enums\User\FollowStatus;
use App\Models\AuthorshipRequest;
use App\Actions\Ad\DeleteAdAction;
use App\Actions\Chat\DeleteChatAction;
use App\Actions\Post\DeletePostAction;
use App\Actions\Chat\DeleteGroupAction;
use Illuminate\Support\Facades\Storage;
use App\Actions\Chat\DeleteMessageAction;
use App\Actions\JobListing\DeleteJobAction;
use App\Actions\Comment\DeleteCommentAction;
use App\Actions\Product\DeleteProductAction;
use App\Actions\Story\DeleteStoryFrameAction;

class DeleteUserAction
{
    private User $userData;

    private $commentPosts = [];

    public function __construct(User $userData)
    {
        $this->userData = $userData;
    }

    public function execute()
    {
        try {
            $this->unfollowAllUsers();
            
            $this->deleteUserPublications();

            $this->deleteUserWallet();

            $this->deleteUserStories();

            $this->deleteUserStoryViews();

            $this->deleteUserProducts();

            $this->deleteUserAds();

            $this->deleteUserJobs();

            $this->deleteUserNotifications();

            $this->deleteUserDevices();

            $this->resetUserChildAccounts();

            $this->deleteUserPayments();

            $this->deleteUserComments();

            $this->deleteUserSocialAccounts();

            $this->deleteUserSettings();

            $this->deleteUserBookmarks();

            $this->deleteUserBusinessAccount();

            $this->deleteSocialLinks();

            $this->deleteUserReports();

            $this->deleteUserHiddenMessages();

            $this->deleteUserHiddenChats();

            $this->deleteUserChatInvites();

            $this->deleteUserParticipatedChats();

            $this->deleteUserParticipatedGroups();

            $this->deleteUserGroups();

            $this->deleteUserAuthorshipRequests();

            if (! $this->userData->hasDefaultAvatar() && ! empty($this->userData->avatar)) {
                Storage::disk(static_storage_disk())->delete($this->userData->avatar);
                Storage::disk(static_storage_disk())->delete($this->userData->cover);
            }

            if (! $this->userData->hasDefaultCover() && ! empty($this->userData->cover)) {
                Storage::disk(static_storage_disk())->delete($this->userData->cover);
            }
            
            return $this->userData->delete();
        } catch (Throwable $th) {
            timeline_log($th->getMessage());
        }
    }

    private function unfollowAllUsers() {

        // Accurate following and followers count of people who are following and being followed by the user.

        $this->userData->followers()->chunk(500, function ($relationships) {
            foreach ($relationships as $relationship) {
                $followingCount = $relationship->follower->followings()->where('status', FollowStatus::FOLLOWING)->count();
                $relationship->follower->following_count = $followingCount;
                $relationship->follower->save();
            }
        });

        $this->userData->followings()->chunk(500, function ($relationships) {
            foreach ($relationships as $relationship) {
                $followersCount = $relationship->following->followers()->where('status', FollowStatus::FOLLOWING)->count();
                $relationship->following->followers_count = $followersCount;
                $relationship->following->save();
            }
        });

        $this->userData->followers()->delete();
        $this->userData->followings()->delete();
    }

    private function deleteUserPublications() {
        Post::with(['media'])->where('user_id', $this->userData->id)->chunk(500, function ($posts) {
            foreach ($posts as $post) {
                (new DeletePostAction($post))->execute();
            }
        });
    }

    private function deleteUserWallet() {
        if($this->userData->wallet) {
            $this->userData->wallet->transactions()->delete();
        }

        $this->userData->wallet()->delete();
    }

    private function deleteUserParticipatedChats() {
        $chats = Chat::where('type', ChatType::DIRECT)->whereHas('participants', function ($query) {
            $query->where('user_id', $this->userData->id);
        })->get();

        foreach ($chats as $chatData) {
            (new DeleteChatAction($chatData))->execute();
        }
    }

    private function deleteUserParticipatedGroups() {
        $chats = Chat::where('type', ChatType::GROUP)->whereHas('participants', function ($query) {
            $query->where('user_id', $this->userData->id);
        })->with(['group'])->get();
        
        foreach ($chats as $chatData) {
            if($chatData->group->user_id == $this->userData->id) {
                (new DeleteChatAction($chatData))->execute();
            }
            else {
                $chatData->participants()->where('user_id', $this->userData->id)->delete();

                $chatData->messages()->where('user_id', $this->userData->id)->chunk(500, function ($messages) {
                    foreach ($messages as $messageData) {
                        (new DeleteMessageAction($messageData))->execute();
                    }
                });
            }
        }
    }

    private function deleteUserGroups() {
        $groups = $this->userData->groups;

        foreach ($groups as $groupData) {
            (new DeleteGroupAction($groupData))->execute();

            // Delete related chat of the group if it exists.

            if($groupData->chat) {
                (new DeleteChatAction($groupData->chat))->execute();
            }
        }
    }

    private function deleteUserStories() {
        $storyData = $this->userData->story;

        if ($storyData) {
            if ($storyData->frames->isNotEmpty()) {
                foreach ($storyData->frames as $frameData) {
                    (new DeleteStoryFrameAction($frameData))->execute();
                }
            }
    
            $storyData->delete();
        }
    }

    private function deleteUserProducts() {
        $this->userData->products()->chunk(500, function ($products) {
            foreach ($products as $productData) {
                (new DeleteProductAction($productData))->execute();
            }
        });
    }

    private function deleteUserAds() {
        $this->userData->advertising()->chunk(500, function ($ads) {
            foreach ($ads as $adData) {
                (new DeleteAdAction($adData))->execute();
            }
        });
    }

    private function deleteUserJobs() {
        $this->userData->jobListings()->chunk(500, function ($jobs) {
            foreach ($jobs as $jobData) {
                (new DeleteJobAction($jobData))->execute();
            }
        });
    }

    private function deleteUserNotifications() {
        $this->userData->notifications()->delete();
    }

    private function deleteUserDevices() {
        $this->userData->devices()->delete();
    }

    private function resetUserChildAccounts() {
        $this->userData->linkedAccounts()->update([
            'owner_account_id' => null
        ]);
    }

    private function deleteUserSettings() {
        $this->userData->securitySettings()->delete();
        $this->userData->privacySettings()->delete();
        $this->userData->permitSettings()->delete();
        $this->userData->emailNotificationSettings()->delete();
        $this->userData->pushNotificationSettings()->delete();
    }

    private function deleteUserPayments() {
        $this->userData->payments()->delete();
    }

    private function deleteUserStoryViews() {
        StoryView::where('user_id', $this->userData->id)->delete();
    }

    private function deleteUserComments() {
        $this->commentPosts = [];

        Comment::where('user_id', $this->userData->id)->chunk(500, function ($comments) {
            foreach ($comments as $commentData) {
                array_push($this->commentPosts, $commentData->post_id);

                (new DeleteCommentAction($commentData))->execute();
            }
        });
        
        // Accurate count of comments.
        
        Post::whereIn('id', array_unique($this->commentPosts))->chunk(500, function ($posts) {
            foreach ($posts as $postData) {
                $postData->comments_count = $postData->comments()->count();
                $postData->save();
            }
        });
    }

    private function deleteUserSocialAccounts() {
        $this->userData->socialAccounts()->delete();
    }

    private function deleteSocialLinks() {
        $this->userData->socialLinks()->delete();
    }

    private function deleteUserReports() {
        $this->userData->reports()->delete();

        Report::where('reporter_id', $this->userData->id)->delete();
    }

    private function deleteUserBookmarks() {
        Bookmark::where('user_id', $this->userData->id)->delete();
    }

    private function deleteUserBusinessAccount() {
        $this->userData->businessAccount()->delete();
    }

    private function deleteUserHiddenMessages() {
        HiddenMessage::where('user_id', $this->userData->id)->delete();
    }

    private function deleteUserHiddenChats() {
        HiddenChat::where('user_id', $this->userData->id)->delete();
    }
    
    private function deleteUserChatInvites() {
        ChatInvite::where('sender_id', $this->userData->id)->orWhere('receiver_id', $this->userData->id);
    }

    private function deleteUserAuthorshipRequests() {
        AuthorshipRequest::where('user_id', $this->userData->id)->delete();
    }
}
