<?php

namespace App\Reports\CostVsPriceMargin;

use App\Models\Currency;
use App\Models\ProductGroup;
use App\Reports\BaseReport;
use App\Services\Reports\CostVsMarginService;

/**
 * PRC-804 — Birleşik Maliyet vs Satış (Marj) raporu (ürün + domain).
 *
 * Her satır: entity (ürün VEYA TLD) · periyot · maliyet · satış · marj · marj %
 * · (gerçekleşen bakışta) satılan adet × toplam marj.
 *
 * İki bakış (`view` filtresi):
 *   - theoretical : katalog maliyet vs satış → teorik marj.
 *   - realized    : ödenmiş satılan servisler × marj → dönemsel gerçek kâr.
 *
 * ProductProfitability BOZULMAZ — o ürün-özel yaşam-boyu aggregate kalır; bu
 * rapor ürün + domaini teorik/gerçekleşen olarak birleştirir (PRC-804 kabul #7).
 */
class CostVsPriceMargin extends BaseReport
{
    protected CostVsMarginService $service;

    public function __construct()
    {
        $this->service = app(CostVsMarginService::class);
    }

    public function getName(): string
    {
        return __('admin/reports.cost_vs_margin_name');
    }

    public function getDescription(): string
    {
        return __('admin/reports.cost_vs_margin_description');
    }

    public function getCategory(): string
    {
        return __('admin/reports.cost_vs_margin_category');
    }

    public function getIcon(): string
    {
        return 'fas fa-scale-balanced';
    }

    public function getRouteName(): string
    {
        return 'cost-vs-price-margin';
    }

    public function getRequiredPermission(): string
    {
        return 'generate reports';
    }

    public function hasChart(): bool
    {
        return true;
    }

    public function getChartType(): ?string
    {
        return 'bar';
    }

    public function getData(array $filters = []): array
    {
        $filters = $this->validateFilters($filters);

        return $this->service->rows($this->normalize($filters));
    }

    public function getChartData(array $filters = []): ?array
    {
        $rows = $this->data;

        // İlk 20 satır — en yüksek marj %'li (service zaten sıralı döner).
        $top = array_slice($rows, 0, 20);

        $labels = array_map(fn ($r) => $r['name'].' ('.$r['currency'].')', $top);
        $margins = array_map(fn ($r) => $r['margin'], $top);

        return [
            'labels' => $labels,
            'datasets' => [
                [
                    'label' => __('admin/reports.cost_vs_margin_column_margin'),
                    'data' => $margins,
                    'backgroundColor' => array_map(
                        fn ($m) => $m < 0 ? 'rgba(220,53,69,0.6)' : 'rgba(25,135,84,0.6)',
                        $margins
                    ),
                    'borderColor' => array_map(
                        fn ($m) => $m < 0 ? 'rgba(220,53,69,1)' : 'rgba(25,135,84,1)',
                        $margins
                    ),
                    'borderWidth' => 1,
                ],
            ],
        ];
    }

    public function getColumns(): array
    {
        return [
            'name' => [
                'title' => __('admin/reports.cost_vs_margin_column_entity'),
                'type' => 'string',
                'sortable' => true,
            ],
            'group' => [
                'title' => __('admin/reports.cost_vs_margin_column_group'),
                'type' => 'string',
                'sortable' => true,
            ],
            'currency' => [
                'title' => __('admin/reports.cost_vs_margin_column_currency'),
                'type' => 'string',
                'sortable' => true,
            ],
            'period_label' => [
                'title' => __('admin/reports.cost_vs_margin_column_period'),
                'type' => 'string',
                'sortable' => true,
            ],
            'cost' => [
                'title' => __('admin/reports.cost_vs_margin_column_cost'),
                'type' => 'currency',
                'sortable' => true,
            ],
            'sale' => [
                'title' => __('admin/reports.cost_vs_margin_column_sale'),
                'type' => 'currency',
                'sortable' => true,
            ],
            'margin' => [
                'title' => __('admin/reports.cost_vs_margin_column_margin'),
                'type' => 'currency',
                'sortable' => true,
            ],
            'margin_pct' => [
                'title' => __('admin/reports.cost_vs_margin_column_margin_pct'),
                'type' => 'percentage',
                'sortable' => true,
            ],
            'sold_qty' => [
                'title' => __('admin/reports.cost_vs_margin_column_sold_qty'),
                'type' => 'number',
                'sortable' => true,
            ],
            'total_margin' => [
                'title' => __('admin/reports.cost_vs_margin_column_total_margin'),
                'type' => 'currency',
                'sortable' => true,
            ],
        ];
    }

    public function getFilters(): array
    {
        return [
            'view' => [
                'type' => 'select',
                'label' => __('admin/reports.cost_vs_margin_filter_view'),
                'required' => false,
                'options' => [
                    'theoretical' => __('admin/reports.cost_vs_margin_view_theoretical'),
                    'realized' => __('admin/reports.cost_vs_margin_view_realized'),
                ],
                'default' => 'theoretical',
            ],
            'entity_type' => [
                'type' => 'select',
                'label' => __('admin/reports.cost_vs_margin_filter_entity_type'),
                'required' => false,
                'options' => [
                    'all' => __('admin/reports.cost_vs_margin_entity_all'),
                    'product' => __('admin/reports.cost_vs_margin_entity_product'),
                    'domain' => __('admin/reports.cost_vs_margin_entity_domain'),
                ],
                'default' => 'all',
            ],
            'currency_id' => [
                'type' => 'select',
                'label' => __('admin/reports.cost_vs_margin_filter_currency'),
                'required' => false,
                'options' => $this->currencyOptions(),
                'default' => (string) ($this->defaultCurrencyId() ?? ''),
            ],
            'product_group_id' => [
                'type' => 'select',
                'label' => __('admin/reports.cost_vs_margin_filter_group'),
                'required' => false,
                'options' => $this->groupOptions(),
                'default' => '',
            ],
            'start_date' => [
                'type' => 'date',
                'label' => __('admin/reports.cost_vs_margin_filter_start_date'),
                'required' => false,
                'default' => now()->subYear()->format('Y-m-d'),
            ],
            'end_date' => [
                'type' => 'date',
                'label' => __('admin/reports.cost_vs_margin_filter_end_date'),
                'required' => false,
                'default' => now()->format('Y-m-d'),
            ],
        ];
    }

    public function getDefaultFilters(): array
    {
        return [
            'view' => 'theoretical',
            'entity_type' => 'all',
            'currency_id' => (string) ($this->defaultCurrencyId() ?? ''),
            'start_date' => now()->subYear()->format('Y-m-d'),
            'end_date' => now()->format('Y-m-d'),
        ];
    }

    public function validateFilters(array $filters): array
    {
        $rules = [
            'view' => 'nullable|in:theoretical,realized',
            'entity_type' => 'nullable|in:all,product,domain',
            'currency_id' => 'nullable|integer',
            'product_group_id' => 'nullable|integer',
            'start_date' => 'nullable|date',
            'end_date' => 'nullable|date|after_or_equal:start_date',
        ];

        $validator = validator($filters, $rules);

        if ($validator->fails()) {
            throw new \InvalidArgumentException($validator->errors()->first());
        }

        return $filters;
    }

    protected function getSummary(): array
    {
        $rows = collect($this->data);
        $totalMargin = $rows->sum('margin');
        $totalCost = $rows->sum('cost');
        $totalSale = $rows->sum('sale');

        return [
            'total_records' => $rows->count(),
            'total_cost' => round((float) $totalCost, 2),
            'total_sale' => round((float) $totalSale, 2),
            'total_margin' => round((float) $totalMargin, 2),
            'avg_margin_pct' => $rows->count() > 0
                ? round((float) $rows->avg('margin_pct'), 2)
                : 0.0,
            'realized_total_margin' => round((float) $rows->sum(fn ($r) => (float) ($r['total_margin'] ?? 0)), 2),
            'generated_at' => now()->toISOString(),
            'filters_applied' => $this->filters,
        ];
    }

    /* --------------------------------------------------------------------- */

    /**
     * @return array<string,mixed>
     */
    protected function normalize(array $filters): array
    {
        return [
            'view' => $filters['view'] ?? 'theoretical',
            'entity_type' => $filters['entity_type'] ?? 'all',
            'currency_id' => isset($filters['currency_id']) && $filters['currency_id'] !== ''
                ? (int) $filters['currency_id'] : null,
            'product_group_id' => isset($filters['product_group_id']) && $filters['product_group_id'] !== ''
                ? (int) $filters['product_group_id'] : null,
            'start_date' => $filters['start_date'] ?? null,
            'end_date' => $filters['end_date'] ?? null,
        ];
    }

    protected function currencyOptions(): array
    {
        return Currency::query()
            ->orderByDesc('is_default')
            ->orderBy('code')
            ->pluck('code', 'id')
            ->mapWithKeys(fn ($code, $id) => [(string) $id => $code])
            ->all();
    }

    protected function groupOptions(): array
    {
        $options = ['' => __('admin/reports.cost_vs_margin_group_all')];

        foreach (ProductGroup::orderBy('name')->pluck('name', 'id') as $id => $name) {
            $options[(string) $id] = $name;
        }

        return $options;
    }

    protected function defaultCurrencyId(): ?int
    {
        return Currency::where('is_default', true)->value('id')
            ?? Currency::query()->value('id');
    }
}
