<?php

namespace App\Services\Stats;

use App\Models\Stats\Daily\StatFinanceDaily;
use App\Models\Stats\Daily\StatSalesDaily;
use App\Models\Stats\Monthly\StatSalesMonthly;
use App\Models\Stats\StatAlert;
use App\Models\Stats\StatKpiTarget;
use App\Models\Tenants\Tenant;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;

class KpiAlertService
{
    /**
     * KPI 목표 대비 실적 체크 → 알림 생성
     */
    public function checkKpiAlerts(): array
    {
        $errors = [];
        $alertsCreated = 0;

        $tenants = Tenant::where('tenant_st_code', '!=', 'none')->get();

        foreach ($tenants as $tenant) {
            try {
                $alertsCreated += $this->checkTenantKpi($tenant->id);
            } catch (\Throwable $e) {
                $errors[] = "tenant={$tenant->id}: {$e->getMessage()}";
                Log::error('stat:check-kpi-alerts 실패', [
                    'tenant_id' => $tenant->id,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        return [
            'alerts_created' => $alertsCreated,
            'errors' => $errors,
        ];
    }

    private function checkTenantKpi(int $tenantId): int
    {
        $now = Carbon::now();
        $year = $now->year;
        $month = $now->month;
        $alertsCreated = 0;

        $targets = StatKpiTarget::where('tenant_id', $tenantId)
            ->where('stat_year', $year)
            ->where(function ($q) use ($month) {
                $q->where('stat_month', $month)->orWhereNull('stat_month');
            })
            ->get();

        foreach ($targets as $target) {
            $currentValue = $this->getCurrentValue($tenantId, $target->domain, $target->metric_code, $year, $month);

            if ($currentValue === null) {
                continue;
            }

            $ratio = $target->target_value > 0
                ? ($currentValue / $target->target_value) * 100
                : 0;

            if ($ratio < 50) {
                $severity = 'critical';
            } elseif ($ratio < 80) {
                $severity = 'warning';
            } else {
                continue; // 80% 이상이면 알림 불필요
            }

            StatAlert::create([
                'tenant_id' => $tenantId,
                'domain' => $target->domain,
                'alert_type' => 'below_target',
                'severity' => $severity,
                'title' => "{$target->description} 목표 미달 (".number_format($ratio, 0).'%)',
                'message' => "KPI '{$target->metric_code}' 현재값: {$currentValue}, 목표값: {$target->target_value} ({$target->unit})",
                'metric_code' => $target->metric_code,
                'current_value' => $currentValue,
                'threshold_value' => $target->target_value,
                'created_at' => now(),
            ]);
            $alertsCreated++;
        }

        return $alertsCreated;
    }

    private function getCurrentValue(int $tenantId, string $domain, string $metricCode, int $year, int $month): ?float
    {
        return match ($domain) {
            'sales' => $this->getSalesMetric($tenantId, $metricCode, $year, $month),
            'finance' => $this->getFinanceMetric($tenantId, $metricCode, $year, $month),
            default => null,
        };
    }

    private function getSalesMetric(int $tenantId, string $metricCode, int $year, int $month): ?float
    {
        $monthly = StatSalesMonthly::where('tenant_id', $tenantId)
            ->where('stat_year', $year)
            ->where('stat_month', $month)
            ->first();

        if (! $monthly) {
            // 월간 미집계 시 일간 합산
            $daily = StatSalesDaily::where('tenant_id', $tenantId)
                ->whereYear('stat_date', $year)
                ->whereMonth('stat_date', $month)
                ->selectRaw('SUM(order_amount) as order_total, SUM(sales_amount) as sales_total')
                ->first();

            return match ($metricCode) {
                'monthly_order_amount' => (float) ($daily->order_total ?? 0),
                'monthly_sales_amount' => (float) ($daily->sales_total ?? 0),
                default => null,
            };
        }

        return match ($metricCode) {
            'monthly_order_amount' => (float) $monthly->order_amount,
            'monthly_sales_amount' => (float) $monthly->sales_amount,
            'monthly_order_count' => (float) $monthly->order_count,
            default => null,
        };
    }

    private function getFinanceMetric(int $tenantId, string $metricCode, int $year, int $month): ?float
    {
        $daily = StatFinanceDaily::where('tenant_id', $tenantId)
            ->whereYear('stat_date', $year)
            ->whereMonth('stat_date', $month)
            ->selectRaw('SUM(deposit_amount) as deposit_total, SUM(withdrawal_amount) as withdrawal_total')
            ->first();

        return match ($metricCode) {
            'monthly_deposit_amount' => (float) ($daily->deposit_total ?? 0),
            'monthly_withdrawal_amount' => (float) ($daily->withdrawal_total ?? 0),
            default => null,
        };
    }
}
