<?php

namespace App\Services\Onboarding;

use App\Models\BrandKit;
use App\Models\Client;
use App\Models\PlatformConnection;
use App\Models\ReportSchedule;
use App\Models\ReportTemplate;
use App\Services\Reports\ReportTemplateDefaults;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class ClientOnboardingService
{
    public function __construct(private readonly ReportTemplateDefaults $templateDefaults)
    {
    }

    /** @return array<string, string> */
    public function steps(): array
    {
        return [
            'client' => 'Müşteri Bilgileri',
            'integrations' => 'API Bağlantıları',
            'brand' => 'Marka Kiti',
            'report' => 'Rapor Planı',
            'complete' => 'Tamamlandı',
        ];
    }

    /** @return array<string, string> */
    public function platforms(): array
    {
        return [
            'google_ads' => 'Google Ads',
            'meta_ads' => 'Meta Ads',
            'search_console' => 'Search Console',
            'ga4' => 'GA4',
        ];
    }

    /** @return array<string, mixed> */
    public function progress(?Client $client): array
    {
        $steps = array_keys($this->steps());
        $current = $client?->onboarding_step ?: 'client';
        $currentIndex = max(0, array_search($current, $steps, true) ?: 0);

        if ($client?->onboarding_status === 'completed') {
            $current = 'complete';
            $currentIndex = count($steps) - 1;
        }

        return [
            'steps' => $this->steps(),
            'current' => $current,
            'current_index' => $currentIndex,
            'percent' => (int) round(($currentIndex / max(1, count($steps) - 1)) * 100),
        ];
    }

    /** @param array<string, mixed> $data */
    public function saveClient(array $data, ?Client $client = null): Client
    {
        return DB::transaction(function () use ($data, $client) {
            $payload = [
                'company_name' => $data['company_name'],
                'contact_person' => $data['contact_person'] ?? null,
                'email' => $data['email'] ?? null,
                'phone' => $data['phone'] ?? null,
                'website' => $data['website'] ?? null,
                'sector' => $data['sector'] ?? null,
                'status' => $data['status'] ?? 'active',
                'currency_code' => strtoupper($data['currency_code'] ?? 'TRY'),
                'timezone' => $data['timezone'] ?? 'Europe/Istanbul',
                'report_language' => $data['report_language'] ?? 'tr',
                'primary_color' => $this->normalizeColor($data['primary_color'] ?? '#111827'),
                'report_recipients' => $this->emailsFromText($data['report_recipients'] ?? ''),
                'notes' => $data['notes'] ?? null,
                'internal_notes' => $data['internal_notes'] ?? null,
                'onboarding_status' => 'in_progress',
                'onboarding_step' => 'integrations',
                'onboarding_meta' => array_merge($client?->onboarding_meta ?: [], [
                    'client_step_saved_at' => now()->toDateTimeString(),
                ]),
            ];

            if ($client) {
                $client->update($payload);
            } else {
                $payload['created_by'] = auth()->id();
                $client = Client::create($payload);
            }

            return $client->refresh();
        });
    }

    /** @param array<string, mixed> $data */
    public function saveConnections(Client $client, array $data): Client
    {
        return DB::transaction(function () use ($client, $data) {
            $selected = collect($data['platforms'] ?? [])
                ->filter(fn ($item) => ! empty($item['enabled']))
                ->all();

            foreach ($selected as $platform => $item) {
                if (! array_key_exists($platform, $this->platforms())) {
                    continue;
                }

                PlatformConnection::updateOrCreate(
                    ['client_id' => $client->id, 'platform' => $platform],
                    [
                        'connection_name' => $item['connection_name'] ?: ($client->company_name.' - '.$this->platforms()[$platform]),
                        'account_id' => $item['account_id'] ?? null,
                        'account_name' => $item['account_name'] ?? null,
                        'status' => filled($item['account_id'] ?? null) ? 'active' : 'draft',
                        'currency_code' => $client->currency_code,
                        'timezone' => $client->timezone,
                        'meta' => [
                            'created_from_onboarding' => true,
                            'needs_oauth' => empty($item['account_id']),
                            'onboarding_note' => $item['note'] ?? null,
                        ],
                    ]
                );
            }

            $client->update([
                'onboarding_status' => 'in_progress',
                'onboarding_step' => 'brand',
                'onboarding_meta' => array_merge($client->onboarding_meta ?: [], [
                    'selected_platforms' => array_keys($selected),
                    'integrations_step_saved_at' => now()->toDateTimeString(),
                ]),
            ]);

            return $client->refresh();
        });
    }

    /** @param array<string, mixed> $data */
    public function saveBrandKit(Client $client, array $data): BrandKit
    {
        return DB::transaction(function () use ($client, $data) {
            if (! empty($data['brand_kit_id'])) {
                $brandKit = BrandKit::where(function ($query) use ($client) {
                    $query->whereNull('client_id')->orWhere('client_id', $client->id);
                })->findOrFail($data['brand_kit_id']);
            } else {
                $brandKit = BrandKit::updateOrCreate(
                    ['client_id' => $client->id, 'name' => $data['name'] ?: $client->company_name.' Marka Kiti'],
                    [
                        'description' => $data['description'] ?? 'Onboarding sihirbazından oluşturuldu.',
                        'agency_name' => $data['agency_name'] ?? 'Datweb',
                        'agency_logo_url' => $data['agency_logo_url'] ?? null,
                        'client_logo_url' => $data['client_logo_url'] ?? null,
                        'primary_color' => $this->normalizeColor($data['primary_color'] ?? $client->primary_color ?? '#111827'),
                        'accent_color' => $this->normalizeColor($data['accent_color'] ?? '#ef5f86'),
                        'secondary_color' => $this->normalizeColor($data['secondary_color'] ?? '#f8fafc'),
                        'text_color' => $this->normalizeColor($data['text_color'] ?? '#111827'),
                        'muted_color' => $this->normalizeColor($data['muted_color'] ?? '#64748b'),
                        'cover_style' => $data['cover_style'] ?? 'gradient',
                        'footer_note' => $data['footer_note'] ?? 'Bu rapor DW Ads Reporter tarafından otomatik oluşturulmuştur.',
                        'contact_email' => $data['contact_email'] ?? null,
                        'contact_phone' => $data['contact_phone'] ?? null,
                        'website_url' => $data['website_url'] ?? null,
                        'is_default' => true,
                        'is_active' => true,
                        'sort_order' => 10,
                    ]
                );
            }

            BrandKit::where('client_id', $client->id)
                ->where('id', '!=', $brandKit->id)
                ->update(['is_default' => false]);

            $brandKit->update(['is_default' => true, 'is_active' => true]);

            $client->update([
                'onboarding_status' => 'in_progress',
                'onboarding_step' => 'report',
                'primary_color' => $brandKit->primary_color ?: $client->primary_color,
                'onboarding_meta' => array_merge($client->onboarding_meta ?: [], [
                    'brand_kit_id' => $brandKit->id,
                    'brand_step_saved_at' => now()->toDateTimeString(),
                ]),
            ]);

            return $brandKit->refresh();
        });
    }

    /** @param array<string, mixed> $data */
    public function saveReportPlan(Client $client, array $data): ReportSchedule
    {
        return DB::transaction(function () use ($client, $data) {
            $type = $data['report_type'] ?? 'weekly';
            $brandKitId = $client->onboarding_meta['brand_kit_id'] ?? $client->defaultBrandKit()?->id;

            $template = null;
            if (! empty($data['report_template_id'])) {
                $template = ReportTemplate::where(function ($query) use ($client) {
                    $query->whereNull('client_id')->orWhere('client_id', $client->id);
                })->find($data['report_template_id']);
            }

            if (! $template) {
                $template = ReportTemplate::create([
                    'client_id' => $client->id,
                    'brand_kit_id' => $brandKitId,
                    'name' => $client->company_name.' '.Str::ucfirst($this->typeLabel($type)).' Rapor Şablonu',
                    'description' => 'Onboarding sihirbazından oluşturulan varsayılan müşteri şablonu.',
                    'type' => $type,
                    'channels' => array_values($data['channels'] ?? array_keys($this->platforms())),
                    'sections' => $this->templateDefaults->defaultSections($type),
                    'settings' => array_merge($this->templateDefaults->defaultSettings(), [
                        'agency_name' => 'Datweb',
                        'primary_color' => $client->primary_color ?: '#111827',
                        'cover_title' => $client->company_name.' Dijital Performans Raporu',
                    ]),
                    'is_default' => true,
                    'is_active' => true,
                    'sort_order' => 10,
                ]);
            }

            $frequency = $data['frequency'] ?? $type;
            $recipients = $this->emailsFromText($data['recipients'] ?? implode(',', $client->report_recipients ?: []));

            $schedule = ReportSchedule::updateOrCreate(
                ['client_id' => $client->id, 'report_template_id' => $template->id, 'frequency' => $frequency],
                [
                    'daily_time' => $data['daily_time'] ?? '09:00',
                    'weekly_day' => (int) ($data['weekly_day'] ?? 1),
                    'monthly_day' => (int) ($data['monthly_day'] ?? 1),
                    'timezone' => $client->timezone ?: 'Europe/Istanbul',
                    'recipients' => $recipients,
                    'cc' => $this->emailsFromText($data['cc'] ?? ''),
                    'bcc' => $this->emailsFromText($data['bcc'] ?? ''),
                    'include_pdf' => ! empty($data['include_pdf']),
                    'include_excel' => ! empty($data['include_excel']),
                    'is_active' => ! empty($data['is_active']),
                    'next_run_at' => $this->nextRunAt($frequency, $data, $client->timezone ?: 'Europe/Istanbul'),
                    'last_status' => 'created_from_onboarding',
                ]
            );

            $client->update([
                'onboarding_status' => 'in_progress',
                'onboarding_step' => 'complete',
                'onboarding_meta' => array_merge($client->onboarding_meta ?: [], [
                    'report_template_id' => $template->id,
                    'report_schedule_id' => $schedule->id,
                    'report_step_saved_at' => now()->toDateTimeString(),
                ]),
            ]);

            return $schedule->refresh();
        });
    }

    public function complete(Client $client): Client
    {
        $client->update([
            'onboarding_status' => 'completed',
            'onboarding_step' => 'complete',
            'onboarding_completed_at' => now(),
            'onboarding_meta' => array_merge($client->onboarding_meta ?: [], [
                'completed_at' => now()->toDateTimeString(),
            ]),
        ]);

        return $client->refresh();
    }

    /** @return array<string, mixed> */
    public function summary(Client $client): array
    {
        return [
            'connections' => $client->platformConnections()->count(),
            'active_connections' => $client->platformConnections()->where('status', 'active')->count(),
            'brand_kits' => $client->brandKits()->count(),
            'report_templates' => ReportTemplate::where('client_id', $client->id)->count(),
            'report_schedules' => $client->reportSchedules()->count(),
            'active_report_schedules' => $client->reportSchedules()->where('is_active', true)->count(),
        ];
    }

    /** @return array<int, string> */
    public function emailsFromText(string|array|null $value): array
    {
        if (is_array($value)) {
            $value = implode(',', $value);
        }

        return collect(preg_split('/[,;\n]+/', (string) $value))
            ->map(fn ($email) => trim($email))
            ->filter(fn ($email) => filter_var($email, FILTER_VALIDATE_EMAIL))
            ->unique()
            ->values()
            ->all();
    }

    private function normalizeColor(?string $value): string
    {
        $value = trim((string) $value);
        return preg_match('/^#[0-9a-fA-F]{6}$/', $value) ? Str::lower($value) : '#111827';
    }

    /** @param array<string, mixed> $data */
    private function nextRunAt(string $frequency, array $data, string $timezone): Carbon
    {
        $now = Carbon::now($timezone);
        $time = $data['daily_time'] ?? '09:00';
        [$hour, $minute] = array_pad(explode(':', $time), 2, 0);

        if ($frequency === 'daily') {
            return $now->copy()->addDay()->setTime((int) $hour, (int) $minute);
        }

        if ($frequency === 'weekly') {
            $days = [1 => 'monday', 2 => 'tuesday', 3 => 'wednesday', 4 => 'thursday', 5 => 'friday', 6 => 'saturday', 7 => 'sunday'];
            $dayName = $days[max(1, min(7, (int) ($data['weekly_day'] ?? 1)))] ?? 'monday';

            return $now->copy()->next($dayName)->setTime((int) $hour, (int) $minute);
        }

        return $now->copy()
            ->addMonthNoOverflow()
            ->day(min(28, max(1, (int) ($data['monthly_day'] ?? 1))))
            ->setTime((int) $hour, (int) $minute);
    }

    private function typeLabel(string $type): string
    {
        return match ($type) {
            'daily' => 'günlük',
            'weekly' => 'haftalık',
            default => 'aylık',
        };
    }
}
