<?php

namespace Database\Seeders;

use App\Models\Post;
use App\Models\User;
use App\Models\Group;
use App\Models\Friend;
use App\Models\Comment;
use App\Models\Setting;
use App\Enums\ImageNames;
use App\Enums\SettingType;
use App\Models\UserProfile;
use App\Models\Announcement;
use App\Models\Conversation;
use Illuminate\Database\Seeder;

class TestSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        $usersCount = 35;
        $groupsCount = 20;
        $postsCount = 100;
        $announcementsCount = 5;

        $settings = Setting::all();

        // User & User Profile Creation
        $users = User::factory($usersCount)->create()->each(function ($user) use ($settings) {
            $profile = UserProfile::factory()->make();
            $user->profile()->save($profile);
            if (fake()->boolean()) {
                $user->image()->create([
                    'url' => fake()->imageUrl(640, 480, "User {$user->id}", true),
                ]);
            }

            foreach ($settings as $setting) {
                switch ($setting->type) {
                    case SettingType::BOOLEAN:
                        $setting->users()->save($user, ['value' => true]);
                        break;
                    default:
                        $setting->users()->save($user, ['value' => '']);
                        break;
                }
            }
        });

        // Friends
        foreach (range(1, $usersCount * rand(1, floor($usersCount / 2))) as $index) {
            Friend::factory()->create();
        }

        // Conversation, Participants & Messages
        $randomUsers = $users->random(rand(floor($usersCount / 3), floor($usersCount / 2)))->shuffle();
        $randomUsers->each(function ($user1) {
            $user1 = $user1->refresh();
            $conversationsCount = rand(5, 20);
            foreach (range(1, $conversationsCount) as $index) {
                $loops = 0;
                $user2 = null;
                do {
                    $isConversationExists = false;
                    $user2 = User::inRandomOrder()->first();
                    while ($user1->id == $user2->id) {
                        $user2 = User::inRandomOrder()->first();
                    }
                    if ($user1->conversations->count() > 0) {
                        foreach ($user1->conversations as $conversation) {
                            $isConversationExists = $conversation->participants->contains(function ($participant) use ($user2) {
                                return $participant->id == $user2->id;
                            });
                            if ($isConversationExists) {
                                break;
                            }
                        }
                    }
                    $loops++;
                    if ($loops > 1000) {
                        break 2;
                    }
                } while ($isConversationExists);
                $conversation = Conversation::create([]);
                $conversation->participants()->saveMany([$user1, $user2]);

                $messagesCount = rand(20, 30);
                $chatTime = now()->subDay(rand(1, 20));
                foreach (range(1, $messagesCount) as $index) {
                    $message = $conversation->messages()->create([
                        'user_id' => fake()->boolean() ? $user1->id : $user2->id,
                        'content' => fake()->realText(),
                        'created_at' => $chatTime,
                        'updated_at' => $chatTime,
                    ]);
                    if (fake()->boolean()) {
                        foreach (range(1, rand(1, 3)) as $index) {
                            $message->images()->create([
                                'url' => fake()->imageUrl(640, 480, "Message {$message->id}", true),
                            ]);
                        }
                    }
                    $chatTime = $chatTime->addMinutes(fake()->numberBetween(1, 30));
                }
            }
        });

        // Group & Group Admin, Members Creation
        Group::factory($groupsCount)->create()->each(function ($group) use ($users, $usersCount) {
            $randomUsers = $users->random(rand(0, $usersCount))->shuffle();
            $randomUsers->reject(function ($user) use ($group) {
                // Prevent Not to Duplicate
                return $user->id == $group->user_id;
            })->each(function ($user) use ($group) {
                $isSeen = fake()->boolean();
                $isAccepted = $isSeen && fake()->boolean();
                $group->members()->save($user, [
                    'is_seen' => $isSeen,
                    'is_accepted' => $isAccepted,
                ]);
            });

            $group->images()->create([
                'name' => ImageNames::PROFILE->value,
                'url' => fake()->imageUrl(640, 480, "Group Profile {$group->id}", true),
            ]);
            $group->images()->create([
                'name' => ImageNames::COVER->value,
                'url' => fake()->imageUrl(640, 480, "Group Cover {$group->id}", true),
            ]);
        });

        // Post & Post Likes
        Post::factory($postsCount)->create()->each(function ($post) {
            $user = User::inRandomOrder()->first();

            $post->likes()->attach($user, [
                'created_at' => now()->subDays(fake()->boolean() ? 0 : rand(0, 20))->subHours(rand(0, 12))->subMinutes(rand(0, 60)),
            ]);

            if (fake()->boolean()) {
                foreach (range(1, rand(1, 6)) as $index) {
                    $post->images()->create([
                        'url' => fake()->imageUrl(640, 480, "Post {$post->id}", true),
                    ]);
                }
            }
        });

        // Comment & Comment Likes
        Comment::factory($postsCount * rand(2, 5))->create()->each(function ($comment) {
            $user = User::inRandomOrder()->first();

            $comment->likes()->attach($user, [
                'created_at' => now()->subDays(fake()->boolean() ? 0 : rand(0, 20))->subHours(rand(0, 12))->subMinutes(rand(0, 60)),
            ]);

            if (fake()->boolean()) {
                foreach (range(1, rand(1, 3)) as $index) {
                    $comment->images()->create([
                        'url' => fake()->imageUrl(640, 480, "Comment {$comment->id}", true),
                    ]);
                }
            }
        });

        // Announcement
        Announcement::factory($announcementsCount)->create()->each(function ($announcement) {
            $announcement->image()->create([
                'url' => fake()->imageUrl(640, 480, "Announcement {$announcement->id}", true),
            ]);
        });
    }
}
