<?php

namespace App\Console\Commands;

use App\Models\Admin;
use App\Models\Bank;
use App\Models\Organization;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Spatie\Activitylog\Models\Activity;

class CleanupIpAddresses extends Command
{
    protected $signature = 'ip:cleanup {--dry-run : Show what would be cleaned without actually deleting}';
    protected $description;

    public function __construct()
    {
        parent::__construct();
        $this->description = 'Anonymize IP addresses older than ' .
            timebank_config('ip_retention.retention_days') . ' days for GDPR compliance';
    }

    public function handle()
    {
        $retentionDays = timebank_config('ip_retention.retention_days', 180);
        $cutoffDate = now()->subDays($retentionDays);
        $isDryRun = $this->option('dry-run');

        $this->info('Starting IP address cleanup...');
        $this->info('Retention period: ' . $retentionDays . ' days');
        $this->info('Cutoff date: ' . $cutoffDate->toDateTimeString());

        if ($isDryRun) {
            $this->warn('DRY RUN MODE - No changes will be made');
        }

        $totalAnonymized = 0;

        // Cleanup profile tables (users, organizations, banks, admins)
        $profileModels = [
            'users' => User::class,
            'organizations' => Organization::class,
            'banks' => Bank::class,
            'admins' => Admin::class,
        ];

        foreach ($profileModels as $tableName => $modelClass) {
            $count = $this->cleanupProfileTable($tableName, $modelClass, $cutoffDate, $isDryRun);
            $totalAnonymized += $count;
        }

        // Cleanup activity log IP addresses
        $activityLogCount = $this->cleanupActivityLog($cutoffDate, $isDryRun);
        $totalAnonymized += $activityLogCount;

        $action = $isDryRun ? 'Would anonymize' : 'Anonymized';
        $this->info("✓ {$action} {$totalAnonymized} IP address records in total.");

        // Log the cleanup action
        if (!$isDryRun) {
            Log::info('IP address cleanup completed', [
                'retention_days' => $retentionDays,
                'cutoff_date' => $cutoffDate->toDateTimeString(),
                'total_anonymized' => $totalAnonymized,
            ]);
        }

        return 0;
    }

    /**
     * Cleanup IP addresses from profile tables
     *
     * @param string $tableName
     * @param string $modelClass
     * @param \Carbon\Carbon $cutoffDate
     * @param bool $isDryRun
     * @return int Number of records anonymized
     */
    protected function cleanupProfileTable(string $tableName, string $modelClass, $cutoffDate, bool $isDryRun): int
    {
        $this->line("\nProcessing {$tableName} table...");

        // Find profiles with last_login_ip that should be anonymized
        $query = $modelClass::whereNotNull('last_login_ip')
            ->where('last_login_ip', '!=', '')
            ->where(function ($q) use ($cutoffDate) {
                // Anonymize if last_login_at is older than cutoff date
                $q->where('last_login_at', '<', $cutoffDate)
                    // Or if last_login_at is null (should not happen, but handle it)
                    ->orWhereNull('last_login_at');
            });

        $count = $query->count();

        if ($count === 0) {
            $this->line("  No IP addresses to anonymize in {$tableName}");
            return 0;
        }

        if ($isDryRun) {
            $this->warn("  Would anonymize {$count} IP addresses in {$tableName}");

            // Show some examples in dry run
            $examples = $query->take(3)->get(['id', 'name', 'last_login_ip', 'last_login_at']);
            if ($examples->isNotEmpty()) {
                $this->line("  Examples:");
                foreach ($examples as $example) {
                    $loginDate = 'never';
                    if ($example->last_login_at) {
                        $loginDate = is_string($example->last_login_at)
                            ? $example->last_login_at
                            : $example->last_login_at->toDateString();
                    }
                    $this->line("    - ID {$example->id} ({$example->name}): {$example->last_login_ip} (last login: {$loginDate})");
                }
            }
        } else {
            // Anonymize by setting to null
            $updated = $query->update(['last_login_ip' => null]);
            $this->info("  ✓ Anonymized {$updated} IP addresses in {$tableName}");
        }

        return $count;
    }

    /**
     * Cleanup IP addresses from activity log
     *
     * @param \Carbon\Carbon $cutoffDate
     * @param bool $isDryRun
     * @return int Number of records anonymized
     */
    protected function cleanupActivityLog($cutoffDate, bool $isDryRun): int
    {
        $this->line("\nProcessing activity_log table...");

        // Find activity logs with IP addresses older than cutoff date
        $query = Activity::whereNotNull('properties->ip')
            ->where('created_at', '<', $cutoffDate);

        $count = $query->count();

        if ($count === 0) {
            $this->line("  No IP addresses to anonymize in activity_log");
            return 0;
        }

        if ($isDryRun) {
            $this->warn("  Would anonymize {$count} IP addresses in activity_log");

            // Show some examples in dry run
            $examples = $query->take(3)->get(['id', 'log_name', 'properties', 'created_at']);
            if ($examples->isNotEmpty()) {
                $this->line("  Examples:");
                foreach ($examples as $example) {
                    $ip = $example->properties['ip'] ?? 'N/A';
                    $this->line("    - ID {$example->id} ({$example->log_name}): {$ip} (date: {$example->created_at->toDateString()})");
                }
            }
        } else {
            // Anonymize by removing IP from properties JSON
            $activities = $query->get();
            $updated = 0;

            foreach ($activities as $activity) {
                $properties = $activity->properties;
                if (isset($properties['ip'])) {
                    unset($properties['ip']);
                    $activity->properties = $properties;
                    $activity->save();
                    $updated++;
                }
            }

            $this->info("  ✓ Anonymized {$updated} IP addresses in activity_log");
        }

        return $count;
    }
}
