<?php

namespace App\Services\Operations;

use App\Models\AgencyManagementReport;
use App\Models\AlertLog;
use App\Models\ApiRequestLog;
use App\Models\Client;
use App\Models\ClientHealthScore;
use App\Models\EmailLog;
use App\Models\GeneratedReport;
use App\Models\OperationTask;
use App\Models\PlatformConnection;
use App\Models\ReportSchedule;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Storage;
use Throwable;

class AgencyManagementReportService
{
    public function dashboard(array $filters = []): array
    {
        $dateFrom = $this->dateFrom($filters);
        $dateTo = $this->dateTo($filters);

        $live = $this->build($dateFrom, $dateTo, $filters['period_type'] ?? 'weekly');

        return [
            'filters' => [
                'period_type' => $filters['period_type'] ?? 'weekly',
                'date_from' => $dateFrom->toDateString(),
                'date_to' => $dateTo->toDateString(),
            ],
            'live' => $live,
            'reports' => AgencyManagementReport::query()
                ->latest('generated_at')
                ->latest('id')
                ->paginate(15),
        ];
    }

    public function generate(array $filters = []): AgencyManagementReport
    {
        $dateFrom = $this->dateFrom($filters);
        $dateTo = $this->dateTo($filters);
        $periodType = $filters['period_type'] ?? 'weekly';

        $report = AgencyManagementReport::create([
            'period_type' => $periodType,
            'date_from' => $dateFrom->toDateString(),
            'date_to' => $dateTo->toDateString(),
            'status' => 'processing',
            'generated_at' => now(),
            'generated_by' => Auth::id(),
        ]);

        try {
            $payload = $this->build($dateFrom, $dateTo, $periodType);
            $paths = $this->writeFiles($report, $payload);

            $report->update([
                'status' => 'completed',
                'overall_score' => $payload['overall_score'],
                'summary' => $payload['summary'],
                'kpis' => $payload['kpis'],
                'risk_clients' => $payload['risk_clients'],
                'top_clients' => $payload['top_clients'],
                'team_workload' => $payload['team_workload'],
                'channel_health' => $payload['channel_health'],
                'recommendations' => $payload['recommendations'],
                'html_path' => $paths['html_path'],
                'csv_path' => $paths['csv_path'],
                'error_message' => null,
            ]);
        } catch (Throwable $exception) {
            $report->update([
                'status' => 'failed',
                'error_message' => $exception->getMessage(),
            ]);
        }

        return $report->fresh();
    }

    public function regenerate(AgencyManagementReport $report): AgencyManagementReport
    {
        $payload = $this->build($report->date_from, $report->date_to, $report->period_type);
        $paths = $this->writeFiles($report, $payload);

        $report->update([
            'status' => 'completed',
            'overall_score' => $payload['overall_score'],
            'summary' => $payload['summary'],
            'kpis' => $payload['kpis'],
            'risk_clients' => $payload['risk_clients'],
            'top_clients' => $payload['top_clients'],
            'team_workload' => $payload['team_workload'],
            'channel_health' => $payload['channel_health'],
            'recommendations' => $payload['recommendations'],
            'html_path' => $paths['html_path'],
            'csv_path' => $paths['csv_path'],
            'generated_at' => now(),
            'error_message' => null,
        ]);

        return $report->fresh();
    }

    public function build(CarbonInterface|string $dateFrom, CarbonInterface|string $dateTo, string $periodType = 'weekly'): array
    {
        $from = $dateFrom instanceof CarbonInterface ? $dateFrom->copy()->startOfDay() : Carbon::parse($dateFrom)->startOfDay();
        $to = $dateTo instanceof CarbonInterface ? $dateTo->copy()->endOfDay() : Carbon::parse($dateTo)->endOfDay();

        $clients = $this->clients();
        $healthCards = $this->healthCards($clients);
        $kpis = $this->kpis($from, $to, $clients, $healthCards);
        $riskClients = $healthCards->whereIn('status', ['critical', 'risk'])->sortBy('score')->take(20)->values()->all();
        $topClients = $healthCards->sortByDesc('score')->take(10)->values()->all();
        $teamWorkload = $this->teamWorkload($from, $to);
        $channelHealth = $this->channelHealth($clients);
        $recommendations = $this->recommendations($kpis, $riskClients, $teamWorkload, $channelHealth);
        $overallScore = $this->overallScore($kpis, $healthCards, $teamWorkload);

        return [
            'period_type' => $periodType,
            'date_from' => $from->toDateString(),
            'date_to' => $to->toDateString(),
            'overall_score' => $overallScore,
            'summary' => [
                'title' => $this->periodTitle($periodType),
                'text' => $this->summaryText($overallScore, $kpis),
                'generated_at' => now()->format('d.m.Y H:i'),
                'range_label' => $from->format('d.m.Y').' - '.$to->format('d.m.Y'),
            ],
            'kpis' => $kpis,
            'risk_clients' => $riskClients,
            'top_clients' => $topClients,
            'team_workload' => $teamWorkload,
            'channel_health' => $channelHealth,
            'recommendations' => $recommendations,
        ];
    }

    protected function clients(): Collection
    {
        if (! class_exists(Client::class) || ! Schema::hasTable('clients')) {
            return collect();
        }

        return Client::query()
            ->with(['platformConnections', 'generatedReports', 'reportSchedules'])
            ->orderBy('company_name')
            ->get();
    }

    protected function healthCards(Collection $clients): Collection
    {
        $service = app(ClientHealthScoreService::class);

        return $clients->map(function (Client $client) use ($service) {
            $card = $service->calculate($client);

            return [
                'client_id' => $client->id,
                'company_name' => $client->company_name,
                'score' => $card['score'],
                'status' => $card['status'],
                'status_label' => $card['status_label'],
                'readiness' => $card['readiness'],
                'risk_count' => count($card['risk_items'] ?? []),
                'risk_items' => array_slice($card['risk_items'] ?? [], 0, 5),
                'recommendations' => array_slice($card['recommendations'] ?? [], 0, 4),
                'url' => route('admin.health-scores.show', $client),
            ];
        });
    }

    protected function kpis(CarbonInterface $from, CarbonInterface $to, Collection $clients, Collection $healthCards): array
    {
        $totalClients = $clients->count();
        $activeClients = $clients->filter(fn ($client) => ($client->status ?? 'active') === 'active')->count();
        $avgHealth = $healthCards->count() ? (int) round($healthCards->avg('score')) : 0;
        $criticalClients = $healthCards->where('status', 'critical')->count();
        $riskClients = $healthCards->whereIn('status', ['critical', 'risk'])->count();

        $reportsGenerated = $this->safeCount(GeneratedReport::class, fn ($query) => $query
            ->whereBetween('created_at', [$from, $to])
        );
        $reportsFailed = $this->safeCount(GeneratedReport::class, fn ($query) => $query
            ->whereBetween('created_at', [$from, $to])
            ->where('status', 'failed')
        );
        $emailsSent = $this->safeCount(EmailLog::class, fn ($query) => $query
            ->whereBetween('created_at', [$from, $to])
            ->whereIn('status', ['sent', 'success', 'completed'])
        );
        $emailsFailed = $this->safeCount(EmailLog::class, fn ($query) => $query
            ->whereBetween('created_at', [$from, $to])
            ->whereIn('status', ['failed', 'error'])
        );
        $apiErrors = $this->safeCount(ApiRequestLog::class, fn ($query) => $query
            ->whereBetween('created_at', [$from, $to])
            ->whereNotNull('error_message')
        );
        $openAlerts = $this->safeCount(AlertLog::class, fn ($query) => $query
            ->whereIn('status', ['open', 'new', 'triggered'])
        );
        $criticalAlerts = $this->safeCount(AlertLog::class, fn ($query) => $query
            ->whereIn('status', ['open', 'new', 'triggered'])
            ->whereIn('severity', ['critical', 'high'])
        );
        $openTasks = $this->safeCount(OperationTask::class, fn ($query) => $query
            ->whereIn('status', ['open', 'in_progress', 'waiting'])
        );
        $overdueTasks = $this->safeCount(OperationTask::class, fn ($query) => $query
            ->whereIn('status', ['open', 'in_progress', 'waiting'])
            ->whereNotNull('due_at')
            ->where('due_at', '<', now())
        );
        $upcomingReports = $this->safeCount(ReportSchedule::class, fn ($query) => $query
            ->where('is_active', true)
            ->whereBetween('next_run_at', [now(), now()->addDays(7)])
        );
        $activeConnections = $this->safeCount(PlatformConnection::class, fn ($query) => $query
            ->where('status', 'active')
        );
        $erroredConnections = $this->safeCount(PlatformConnection::class, fn ($query) => $query
            ->whereNotNull('last_error')
        );

        return [
            'total_clients' => $totalClients,
            'active_clients' => $activeClients,
            'average_health_score' => $avgHealth,
            'critical_clients' => $criticalClients,
            'risk_clients' => $riskClients,
            'reports_generated' => $reportsGenerated,
            'reports_failed' => $reportsFailed,
            'emails_sent' => $emailsSent,
            'emails_failed' => $emailsFailed,
            'api_errors' => $apiErrors,
            'open_alerts' => $openAlerts,
            'critical_alerts' => $criticalAlerts,
            'open_tasks' => $openTasks,
            'overdue_tasks' => $overdueTasks,
            'upcoming_reports' => $upcomingReports,
            'active_connections' => $activeConnections,
            'errored_connections' => $erroredConnections,
        ];
    }

    protected function teamWorkload(CarbonInterface $from, CarbonInterface $to): array
    {
        if (! class_exists(OperationTask::class) || ! Schema::hasTable('operation_tasks')) {
            return ['users' => [], 'by_priority' => [], 'by_status' => []];
        }

        $tasks = OperationTask::query()
            ->with('assignee')
            ->whereBetween('created_at', [$from, $to])
            ->orWhere(function (Builder $query) {
                $query->whereIn('status', ['open', 'in_progress', 'waiting']);
            })
            ->get();

        return [
            'users' => $tasks->groupBy('assigned_to')->map(function (Collection $items, $userId) {
                $assignee = optional($items->first()->assignee)->name ?: 'Atanmamış';

                return [
                    'user_id' => $userId,
                    'name' => $assignee,
                    'open' => $items->whereIn('status', ['open', 'in_progress', 'waiting'])->count(),
                    'completed' => $items->where('status', 'completed')->count(),
                    'critical' => $items->where('priority', 'critical')->count(),
                    'overdue' => $items->filter(fn ($task) => $task->due_at && $task->due_at->isPast() && ! in_array($task->status, ['completed', 'cancelled'], true))->count(),
                ];
            })->sortByDesc('open')->values()->all(),
            'by_priority' => $tasks->groupBy('priority')->map->count()->all(),
            'by_status' => $tasks->groupBy('status')->map->count()->all(),
        ];
    }

    protected function channelHealth(Collection $clients): array
    {
        $connections = class_exists(PlatformConnection::class) && Schema::hasTable('platform_connections')
            ? PlatformConnection::query()->get()
            : collect();

        return collect(['google_ads', 'meta_ads', 'search_console', 'ga4'])->mapWithKeys(function (string $platform) use ($connections) {
            $items = $connections->where('platform', $platform);
            $total = $items->count();
            $active = $items->where('status', 'active')->count();
            $errors = $items->filter(fn ($connection) => ! empty($connection->last_error))->count();
            $score = $total > 0 ? max(0, (int) round(($active / $total) * 100) - ($errors * 10)) : 0;

            return [$platform => [
                'label' => $this->platformLabel($platform),
                'total' => $total,
                'active' => $active,
                'errors' => $errors,
                'score' => $score,
            ]];
        })->all();
    }

    protected function recommendations(array $kpis, array $riskClients, array $teamWorkload, array $channelHealth): array
    {
        $recommendations = [];

        if (($kpis['critical_clients'] ?? 0) > 0) {
            $recommendations[] = 'Kritik durumdaki müşteriler için bugün ayrı operasyon listesi çıkarılmalı.';
        }

        if (($kpis['emails_failed'] ?? 0) > 0) {
            $recommendations[] = 'Başarısız mail gönderimleri kontrol edilmeli; SMTP, alıcı adresleri ve ek dosya boyutları incelenmeli.';
        }

        if (($kpis['api_errors'] ?? 0) > 0 || ($kpis['errored_connections'] ?? 0) > 0) {
            $recommendations[] = 'API hata logları ve token geçerlilikleri kontrol edilmeli; sorunlu bağlantılar tekrar yetkilendirilmeli.';
        }

        if (($kpis['overdue_tasks'] ?? 0) > 0) {
            $recommendations[] = 'Geciken görevler müşteri temsilcilerine atanmalı ve gün sonuna kadar kapatılmalı.';
        }

        foreach ($channelHealth as $platform => $item) {
            if (($item['score'] ?? 100) < 70 && ($item['total'] ?? 0) > 0) {
                $recommendations[] = $item['label'].' bağlantı sağlığı düşük; bu kanal için toplu bağlantı testi çalıştırılmalı.';
            }
        }

        if (count($recommendations) === 0) {
            $recommendations[] = 'Genel operasyon sağlıklı görünüyor; haftalık rapor gönderimleri ve sağlık skorları rutin şekilde izlenebilir.';
        }

        return array_values(array_unique($recommendations));
    }

    protected function overallScore(array $kpis, Collection $healthCards, array $teamWorkload): int
    {
        $base = $kpis['average_health_score'] ?? 0;

        $penalty = 0;
        $penalty += min(25, (int) ($kpis['critical_clients'] ?? 0) * 8);
        $penalty += min(15, (int) ($kpis['emails_failed'] ?? 0) * 3);
        $penalty += min(18, (int) ($kpis['api_errors'] ?? 0));
        $penalty += min(20, (int) ($kpis['overdue_tasks'] ?? 0) * 3);

        return max(0, min(100, (int) round($base - $penalty / 2)));
    }

    protected function writeFiles(AgencyManagementReport $report, array $payload): array
    {
        $dir = 'agency-management-reports/'.$report->id;
        Storage::disk('public')->makeDirectory($dir);

        $html = view('admin.management-reports.print', ['report' => $report, 'payload' => $payload])->render();
        $csv = $this->csv($payload);

        $htmlPath = $dir.'/management-report.html';
        $csvPath = $dir.'/management-report.csv';

        Storage::disk('public')->put($htmlPath, $html);
        Storage::disk('public')->put($csvPath, $csv);

        return [
            'html_path' => $htmlPath,
            'csv_path' => $csvPath,
        ];
    }

    protected function csv(array $payload): string
    {
        $lines = [];
        $lines[] = ['Alan', 'Değer'];

        foreach ($payload['kpis'] as $key => $value) {
            $lines[] = [$key, is_scalar($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE)];
        }

        $lines[] = [];
        $lines[] = ['Riskli Müşteriler'];
        $lines[] = ['Müşteri', 'Skor', 'Durum', 'Risk Sayısı'];

        foreach ($payload['risk_clients'] as $client) {
            $lines[] = [$client['company_name'] ?? '', $client['score'] ?? '', $client['status_label'] ?? '', $client['risk_count'] ?? ''];
        }

        return collect($lines)->map(function (array $row) {
            return collect($row)->map(function ($cell) {
                $cell = (string) $cell;
                return '"'.str_replace('"', '""', $cell).'"';
            })->implode(',');
        })->implode("\n");
    }

    protected function safeCount(string $model, callable $callback): int
    {
        try {
            if (! class_exists($model)) {
                return 0;
            }

            $instance = new $model();
            if (! Schema::hasTable($instance->getTable())) {
                return 0;
            }

            $query = $model::query();
            $callback($query);

            return (int) $query->count();
        } catch (Throwable) {
            return 0;
        }
    }

    protected function dateFrom(array $filters): Carbon
    {
        if (! empty($filters['date_from'])) {
            return Carbon::parse($filters['date_from'])->startOfDay();
        }

        return match ($filters['period_type'] ?? 'weekly') {
            'daily' => now()->subDay()->startOfDay(),
            'monthly' => now()->subMonth()->startOfMonth(),
            default => now()->subDays(7)->startOfDay(),
        };
    }

    protected function dateTo(array $filters): Carbon
    {
        if (! empty($filters['date_to'])) {
            return Carbon::parse($filters['date_to'])->endOfDay();
        }

        return match ($filters['period_type'] ?? 'weekly') {
            'daily' => now()->subDay()->endOfDay(),
            'monthly' => now()->subMonth()->endOfMonth(),
            default => now()->subDay()->endOfDay(),
        };
    }

    protected function periodTitle(string $periodType): string
    {
        return match ($periodType) {
            'daily' => 'Günlük Ajans Operasyon Özeti',
            'monthly' => 'Aylık Ajans Yönetim Raporu',
            default => 'Haftalık Ajans Yönetim Raporu',
        };
    }

    protected function summaryText(int $score, array $kpis): string
    {
        if ($score >= 85) {
            return 'Ajans operasyon sağlığı iyi durumda. Rutin takip ve rapor gönderim kontrolleri yeterli görünüyor.';
        }

        if ($score >= 65) {
            return 'Genel yapı çalışıyor ancak riskli müşteri, API hatası veya geciken görevler için operasyon kontrolü önerilir.';
        }

        return 'Ajans operasyonunda kritik kontrol ihtiyacı var. Öncelik API/token hataları, geciken görevler ve riskli müşterilere verilmelidir.';
    }

    protected function platformLabel(string $platform): string
    {
        return match ($platform) {
            'google_ads' => 'Google Ads',
            'meta_ads' => 'Meta Ads',
            'search_console' => 'Search Console',
            'ga4' => 'GA4',
            default => strtoupper($platform),
        };
    }
}
