<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\Post;
use App\Models\Friend;
use App\Models\JobApplication;
use App\Models\Comment;
use App\Models\Like;
use App\Models\Notification;
use App\Models\Blacklist;
use App\Models\Blog;
use App\Models\Group;
use App\Models\Page;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\SitemapGenerator;
use Spatie\Sitemap\Tags\Url;
use App\Jobs\SendBulkEmailJob;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Collection;

class ToolsController extends Controller
{
    /**
     * Display the data deletion tools page
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('admin.pages.tools.index');
    }

    /**
     * Process data deletion based on selected criteria
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function deleteData(Request $request)
    {
        $request->validate([
            'delete_option' => 'required|integer|between:1,12',
        ]);

        $option = $request->input('delete_option');
        $count = 0;
        $message = '';

        try {
            DB::beginTransaction();

            switch ($option) {
                // User deletion options
                case 1: // Delete all inactive users
                    $count = $this->deleteInactiveUsers();
                    $message = 'Inactive users deleted successfully';
                    break;
                
                case 2: // Delete users not logged in for more than 1 week
                    $count = $this->deleteInactiveUsersByTime(7);
                    $message = 'Users inactive for more than 1 week deleted successfully';
                    break;
                
                case 3: // Delete users not logged in for more than 1 month
                    $count = $this->deleteInactiveUsersByTime(30);
                    $message = 'Users inactive for more than 1 month deleted successfully';
                    break;
                
                case 4: // Delete users not logged in for more than 1 year
                    $count = $this->deleteInactiveUsersByTime(365);
                    $message = 'Users inactive for more than 1 year deleted successfully';
                    break;
                
                // Post deletion options
                case 5: // Delete posts older than 1 week
                    $count = $this->deleteOldPosts(7);
                    $message = 'Posts older than 1 week deleted successfully';
                    break;
                
                case 6: // Delete posts older than 1 month
                    $count = $this->deleteOldPosts(30);
                    $message = 'Posts older than 1 month deleted successfully';
                    break;
                
                case 7: // Delete posts older than 1 year
                    $count = $this->deleteOldPosts(365);
                    $message = 'Posts older than 1 year deleted successfully';
                    break;
                
                // Friend/connection deletion options
                case 8: // Delete pending friend requests older than 1 month
                    $count = $this->deleteOldFriendRequests(30);
                    $message = 'Pending friend requests older than 1 month deleted successfully';
                    break;
                
                // Comment deletion options
                case 9: // Delete comments older than 1 month
                    $count = $this->deleteOldComments(30);
                    $message = 'Comments older than 1 month deleted successfully';
                    break;
                
                // Notification deletion options
                case 10: // Delete notifications older than 1 month
                    $count = $this->deleteOldNotifications(30);
                    $message = 'Notifications older than 1 month deleted successfully';
                    break;
                
                // Job application deletion options
                case 11: // Delete rejected job applications older than 3 months
                    $count = $this->deleteOldJobApplications(90, 'rejected');
                    $message = 'Rejected job applications older than 3 months deleted successfully';
                    break;
                
                case 12: // Delete all expired job applications
                    $count = $this->deleteExpiredJobApplications();
                    $message = 'Expired job applications deleted successfully';
                    break;
            }

            DB::commit();
            
            return redirect()->route('admin.tools.index')
                ->with('success', $message . ' (' . $count . ' records affected)');
                
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Data deletion error: ' . $e->getMessage());
            
            return redirect()->route('admin.tools.index')
                ->with('error', 'An error occurred during data deletion: ' . $e->getMessage());
        }
    }

    /**
     * Delete users with inactive status
     *
     * @return int Number of deleted users
     */
    private function deleteInactiveUsers()
    {
        return User::where('status', 0)->delete();
    }

    /**
     * Delete users who haven't logged in for a specified number of days
     *
     * @param int $days Number of days of inactivity
     * @return int Number of deleted users
     */
    private function deleteInactiveUsersByTime($days)
    {
        $date = Carbon::now()->subDays($days);
        return User::where('last_login', '<', $date)->delete();
    }

    /**
     * Delete posts older than a specified number of days
     *
     * @param int $days Age of posts in days
     * @return int Number of deleted posts
     */
    private function deleteOldPosts($days)
    {
        $date = Carbon::now()->subDays($days);
        return Post::where('created_at', '<', $date)->delete();
    }

    /**
     * Delete pending friend requests older than a specified number of days
     *
     * @param int $days Age of friend requests in days
     * @return int Number of deleted friend requests
     */
    private function deleteOldFriendRequests($days)
    {
        $date = Carbon::now()->subDays($days);
        return Friend::where('status', 'pending')
            ->where('created_at', '<', $date)
            ->delete();
    }

    /**
     * Delete comments older than a specified number of days
     *
     * @param int $days Age of comments in days
     * @return int Number of deleted comments
     */
    private function deleteOldComments($days)
    {
        $date = Carbon::now()->subDays($days);
        return Comment::where('created_at', '<', $date)->delete();
    }

    /**
     * Delete notifications older than a specified number of days
     *
     * @param int $days Age of notifications in days
     * @return int Number of deleted notifications
     */
    private function deleteOldNotifications($days)
    {
        $date = Carbon::now()->subDays($days);
        return Notification::where('created_at', '<', $date)->delete();
    }

    /**
     * Delete job applications with specific status older than a specified number of days
     *
     * @param int $days Age of job applications in days
     * @param string $status Status of job applications to delete
     * @return int Number of deleted job applications
     */
    private function deleteOldJobApplications($days, $status)
    {
        $date = Carbon::now()->subDays($days);
        return JobApplication::where('status', $status)
            ->where('created_at', '<', $date)
            ->delete();
    }

    /**
     * Delete job applications for expired jobs
     *
     * @return int Number of deleted job applications
     */
    private function deleteExpiredJobApplications()
    {
        return JobApplication::whereHas('job', function($query) {
            $query->where('expiry_date', '<', Carbon::now());
        })->delete();
    }

    /**
     * Display the database backup page
     *
     * @return \Illuminate\Http\Response
     */
    public function backupDatabase()
    {
        return view('admin.pages.tools.backup');
    }

    /**
     * Generate a database backup
     *
     * @return \Illuminate\Http\Response
     */
    public function generateBackup()
    {
        try {
            $backupPath = storage_path('app/backups');
            if (!File::exists($backupPath)) {
                File::makeDirectory($backupPath, 0755, true);
            }

            $databaseName = DB::getDatabaseName();
            $tables = DB::select("SHOW TABLES");
            $tableKey = "Tables_in_{$databaseName}";
            $sqlDump = "";

            foreach ($tables as $tableObj) {
                $table = $tableObj->$tableKey;

                // Get CREATE TABLE
                $create = DB::select("SHOW CREATE TABLE `$table`");
                $sqlDump .= "\n\n" . $create[0]->{'Create Table'} . ";\n\n";

                // Get table data
                $rows = DB::table($table)->get();
                if ($rows->count() > 0) {
                    $columnNames = array_keys((array)$rows[0]);
                    $sqlDump .= "INSERT INTO `$table` (`" . implode("`, `", $columnNames) . "`) VALUES\n";

                    $valueLines = [];
                    foreach ($rows as $row) {
                        $values = array_map(function ($value) {
                            if (is_null($value)) return 'NULL';
                            return "'" . str_replace("'", "''", $value) . "'";
                        }, (array)$row);

                        $valueLines[] = "(" . implode(", ", $values) . ")";
                    }

                    $sqlDump .= implode(",\n", $valueLines) . ";\n";
                }
            }

            $backupFileName = 'backup_' . Carbon::now()->format('Y-m-d_H-i-s') . '.sql';
            Storage::disk('local')->put('backups/' . $backupFileName, $sqlDump);

            return redirect()->route('admin.tools.backup')
                ->with('success', 'Database SQL backup created successfully: ' . $backupFileName);
                
        } catch (\Exception $e) {
            Log::error('Database backup error: ' . $e->getMessage());

            return redirect()->route('admin.tools.backup')
                ->with('error', 'Database SQL backup failed: ' . $e->getMessage());
        }
    }

    /**
     * List all available backups
     *
     * @return \Illuminate\Http\Response
     */
    public function listBackups()
    {
        $backupPath = storage_path('app/backups');
        $backups = [];
        
        if (file_exists($backupPath)) {
            $files = scandir($backupPath);
            
            foreach ($files as $file) {
                if ($file != '.' && $file != '..' && pathinfo($file, PATHINFO_EXTENSION) == 'sql') {
                    $backups[] = [
                        'name' => $file,
                        'size' => $this->formatBytes(filesize($backupPath . '/' . $file)),
                        'date' => date('Y-m-d H:i:s', filemtime($backupPath . '/' . $file))
                    ];
                }
            }
        }
        
        return view('admin.pages.tools.backups', compact('backups'));
    }

    /**
     * Format bytes to human-readable format
     *
     * @param int $bytes Number of bytes
     * @param int $precision Precision of formatting
     * @return string Formatted size
     */
    private function formatBytes($bytes, $precision = 2)
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);
        
        $bytes /= pow(1024, $pow);
        
        return round($bytes, $precision) . ' ' . $units[$pow];
    }

    /**
     * Download a database backup file
     *
     * @param string $filename The name of the backup file to download
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
     */
    public function downloadBackup($filename)
    {
        try {
            $backupPath = storage_path('app/backups');
            $filePath = $backupPath . '/' . $filename;
            
            if (!file_exists($filePath)) {
                return redirect()->route('admin.tools.backups')
                    ->with('error', 'Backup file not found.');
            }
            
            return response()->download($filePath);
            
        } catch (\Exception $e) {
            Log::error('Backup download error: ' . $e->getMessage());
            
            return redirect()->route('admin.tools.backups')
                ->with('error', 'Failed to download backup: ' . $e->getMessage());
        }
    }

    /**
     * Delete a database backup file
     *
     * @param string $filename The name of the backup file to delete
     * @return \Illuminate\Http\RedirectResponse
     */
    public function deleteBackup($filename)
    {
        try {
            $backupPath = storage_path('app/backups');
            $filePath = $backupPath . '/' . $filename;
            
            if (!file_exists($filePath)) {
                return redirect()->route('admin.tools.backups')
                    ->with('error', 'Backup file not found.');
            }
            
            unlink($filePath);
            
            return redirect()->route('admin.tools.backups')
                ->with('success', 'Backup deleted successfully.');
                
        } catch (\Exception $e) {
            Log::error('Backup deletion error: ' . $e->getMessage());
            
            return redirect()->route('admin.tools.backups')
                ->with('error', 'Failed to delete backup: ' . $e->getMessage());
        }
    }

    /**
     * Display the blacklist management page
     *
     * @return \Illuminate\Http\Response
     */
    public function blacklist()
    {
        $blacklisted = Blacklist::orderBy('created_at', 'desc')->paginate(15);
        return view('admin.pages.tools.blacklist', compact('blacklisted'));
    }

    /**
     * Add a new entry to the blacklist
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function addToBlacklist(Request $request)
    {
        $request->validate([
            'value' => 'required|string|max:255',
            'type' => 'required|in:ip,email,username,email_domain',
        ]);

        $value = trim($request->input('value'));
        $type = $request->input('type');
        
        // Check if already blacklisted
        if (Blacklist::isBlacklisted($value, $type)) {
            return redirect()->route('admin.tools.blacklist')
                ->with('error', 'This value is already blacklisted.');
        }
        
        // Validate based on type
        if ($type == 'ip' && !filter_var($value, FILTER_VALIDATE_IP)) {
            return redirect()->route('admin.tools.blacklist')
                ->with('error', 'Invalid IP address format.');
        } elseif ($type == 'email' && !filter_var($value, FILTER_VALIDATE_EMAIL)) {
            return redirect()->route('admin.tools.blacklist')
                ->with('error', 'Invalid email address format.');
        } elseif ($type == 'email_domain') {
            // Simple domain validation
            if (!preg_match('/^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/', $value)) {
                return redirect()->route('admin.tools.blacklist')
                    ->with('error', 'Invalid email domain format. Use format like "example.com"');
            }
        }
        
        // Add to blacklist
        Blacklist::create([
            'value' => $value,
            'type' => $type,
        ]);
        
        return redirect()->route('admin.tools.blacklist')
            ->with('success', 'Successfully added to blacklist.');
    }

    /**
     * Remove an entry from the blacklist
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function removeFromBlacklist($id)
    {
        Blacklist::findOrFail($id)->delete();
        
        return redirect()->route('admin.tools.blacklist')
            ->with('success', 'Successfully removed from blacklist.');
    }

    /**
     * Remove multiple entries from the blacklist
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function removeMultipleFromBlacklist(Request $request)
    {
        $request->validate([
            'ids' => 'required|array',
            'ids.*' => 'integer',
        ]);
        
        $ids = $request->input('ids');
        Blacklist::whereIn('id', $ids)->delete();
        
        return response()->json([
            'status' => 'success',
            'message' => 'Selected entries removed from blacklist.',
        ]);
    }

    /**
     * Search the blacklist
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function searchBlacklist(Request $request)
    {
        $query = $request->input('query');
        
        $blacklisted = Blacklist::where('value', 'like', "%{$query}%")
            ->orderBy('created_at', 'desc')
            ->paginate(15);
            
        return view('admin.pages.tools.blacklist', compact('blacklisted', 'query'));
    }

    /**
     * Display the fake user generator page
     *
     * @return \Illuminate\Http\Response
     */
    public function fakeUserGenerator()
    {
        $fakeUsersCount = User::where('is_fake', true)->count();
        return view('admin.pages.tools.fake-user-generator', compact('fakeUsersCount'));
    }

    /**
     * Generate fake users
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function generateFakeUsers(Request $request)
    {
        $request->validate([
            'count_users' => 'required|integer|min:1|max:100',
            'password' => 'nullable|string|min:6',
            'avatar' => 'required|boolean',
        ]);

        $count = $request->input('count_users', 10);
        $password = $request->input('password') ?: '123456789';
        $createAvatars = (bool) $request->input('avatar', 0);

        try {
            DB::beginTransaction();
            
            $faker = \Faker\Factory::create();
            $usersCreated = 0;
            
            for ($i = 0; $i < $count; $i++) {
                $gender = $faker->randomElement(['male', 'female']);
                $firstName = $gender === 'male' ? $faker->firstNameMale : $faker->firstNameFemale;
                $lastName = $faker->lastName;
                $username = strtolower($firstName . $lastName . $faker->randomNumber(3));
                
                // Check if username exists
                if (User::where('username', $username)->exists()) {
                    $username = strtolower($firstName . $lastName . $faker->randomNumber(4));
                }
                
                $user = User::create([
                    'username' => $username,
                    'name' => $firstName . ' ' . $lastName,
                    'first_name' => $firstName,
                    'last_name' => $lastName,
                    'email' => $faker->safeEmail(),
                    'password' => bcrypt($password),
                    'gender' => $gender,
                    'date_of_birth' => $faker->dateTimeBetween('-40 years', '-18 years'),
                    'address' => $faker->address,
                    'bio' => $faker->realText(200),
                    'last_ip' => $faker->ipv4,
                    'login_count' => $faker->numberBetween(1, 50),
                    'last_login' => $faker->dateTimeBetween('-30 days', 'now'),
                    'status' => 1,
                    'is_fake' => true,
                    'email_verified_at' => now(),
                ]);
                
                // Create random avatar if enabled
                if ($createAvatars) {
                    // For male and female we'll use different avatar sets
                    $avatarUrl = $gender === 'male' 
                        ? "https://randomuser.me/api/portraits/men/{$faker->numberBetween(0, 99)}.jpg"
                        : "https://randomuser.me/api/portraits/women/{$faker->numberBetween(0, 99)}.jpg";
                    
                    // Save avatar path 
                    // Note: In a real implementation, you might want to download the image
                    // and store it locally, but for simplicity, we'll just store the URL
                    $user->avatar = $avatarUrl;
                    $user->save();
                }
                
                // Assign default user role
                $user->assignRole('user');
                
                $usersCreated++;
            }
            
            DB::commit();
            
            return redirect()->route('admin.tools.fake-user-generator')
                ->with('success', "Successfully generated {$usersCreated} fake users");
                
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Fake user generation error: ' . $e->getMessage());
            
            return redirect()->route('admin.tools.fake-user-generator')
                ->with('error', 'Failed to generate fake users: ' . $e->getMessage());
        }
    }

    /**
     * Delete all fake users
     *
     * @return \Illuminate\Http\Response
     */
    public function deleteAllFakeUsers()
    {
        try {
            $count = User::where('is_fake', true)->count();
            User::where('is_fake', true)->delete();
            
            return redirect()->route('admin.tools.fake-user-generator')
                ->with('success', "Successfully deleted {$count} fake users");
                
        } catch (\Exception $e) {
            Log::error('Delete fake users error: ' . $e->getMessage());
            
            return redirect()->route('admin.tools.fake-user-generator')
                ->with('error', 'Failed to delete fake users: ' . $e->getMessage());
        }
    }

    public function sitemap(){
        return view('admin.pages.tools.sitemap');
    }

    public function generateSitemap(Request $request)
    {
        $request->validate([
            'frequency' => 'required|in:always,hourly,daily,weekly,monthly,yearly,never',
        ]);

        try {
            $sitemap = Sitemap::create();

            // Static URLs
            $sitemap->add(Url::create('/')
                ->setChangeFrequency($request->frequency)
                ->setLastModificationDate(Carbon::now()));
            
            $sitemap->add(Url::create('/about'));
            $sitemap->add(Url::create('/contact'));

            // Blogs
            $blogs = Blog::all();
            foreach ($blogs as $blog) {
                $sitemap->add(Url::create("/blog/{$blog->slug}")
                    ->setLastModificationDate($blog->updated_at)
                    ->setChangeFrequency($request->frequency));
            }

            // Groups
            $groups = Group::all();
            foreach ($groups as $group) {
                $sitemap->add(Url::create("/group/{$group->page_username}")
                    ->setLastModificationDate($group->updated_at)
                    ->setChangeFrequency($request->frequency));
            }

            // Pages
            $pages = Page::all();
            foreach ($pages as $page) {
                $sitemap->add(Url::create("/page/{$page->slug}")
                    ->setLastModificationDate($page->updated_at)
                    ->setChangeFrequency($request->frequency));
            }

            // Write to file
            $sitemap->writeToFile(public_path('sitemap.xml'));

            // Save selected frequency (optional)
            File::put(storage_path('app/sitemap_frequency.txt'), $request->frequency);

            return back()->with('success', 'Sitemap generated successfully.');
        } catch (\Exception $e) {
            return back()->with('error', 'Error generating sitemap: ' . $e->getMessage());
        }
    }

    /**
     * Show the email form
     */
    public function showEmailForm()
    {
        return view('admin.pages.tools.sendEmail');
    }

    /**
     * Send emails to users
     */
    public function sendEmail(Request $request)
    {
        $request->validate([
            'subject' => 'required|string|max:255',
            'message' => 'required|string',
            'user_type' => 'required|string|in:all,active,inactive,week,month,3months,6months,12months,specific',
            'specific_users' => 'nullable|string',
            'test_message' => 'nullable|boolean'
        ]);

        try {
            // Get users query based on type
            $query = User::query();
            
            switch ($request->user_type) {
                case 'active':
                    $query->where('status', 1);
                    break;
                case 'inactive':
                    $query->where('status', 0);
                    break;
                case 'week':
                    $query->where('last_login', '<', now()->subWeek());
                    break;
                case 'month':
                    $query->where('last_login', '<', now()->subMonth());
                    break;
                case '3months':
                    $query->where('last_login', '<', now()->subMonths(3));
                    break;
                case '6months':
                    $query->where('last_login', '<', now()->subMonths(6));
                    break;
                case '12months':
                    $query->where('last_login', '<', now()->subYear());
                    break;
                case 'specific':
                    if ($request->specific_users) {
                        $users = explode(',', $request->specific_users);
                        $query->where(function($q) use ($users) {
                            $q->whereIn('email', $users)
                              ->orWhereIn('username', $users);
                        });
                    }
                    break;
            }

            $users = $query->get();

            if ($users->isEmpty()) {
                return back()->with('error', 'No users found matching the selected criteria.');
            }

            // If test message is checked, send only to admin
            if ($request->test_message) {
                $admin = Auth::user();
                SendBulkEmailJob::dispatch(Collection::make([$admin]), $request->subject, $request->message);
                return back()->with('success', 'Test email has been sent to your email address.');
            }

            // Dispatch job to send emails in chunks
            $chunks = $users->chunk(100);
            foreach ($chunks as $chunk) {
                SendBulkEmailJob::dispatch($chunk, $request->subject, $request->message);
            }

            return back()->with('success', 'Emails are being sent to ' . $users->count() . ' users.');

        } catch (\Exception $e) {
            Log::error('Email sending error: ' . $e->getMessage());
            return back()->with('error', 'Failed to send emails. Please try again.');
        }
    }
}