<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Border;
use Illuminate\Support\Facades\Log;

abstract class BaseExport implements FromCollection, WithHeadings, WithMapping, WithStyles, WithColumnFormatting, WithTitle, ShouldAutoSize
{
    protected $query;
    protected $columns;
    protected $filters;
    protected $title;

    public function __construct($query = null, $filters = [])
    {
        // Handle case where options array is passed from ExportExcelAction
        if (is_array($query) && isset($query['query'])) {
            $this->query = $query['query'];
            $this->filters = $query['filters'] ?? [];
        } elseif (is_array($query)) {
            // If it's an array without 'query' key, treat it as filters
            $this->query = null;
            $this->filters = $query;
        } else {
            $this->query = $query;
            $this->filters = $filters;
        }
        
        $this->columns = $this->getExportColumns();
        $this->title = $this->getExportTitle();
    }

    abstract protected function getExportColumns(): array;

    abstract protected function getExportTitle(): string;

    public function collection()
    {
        $query = $this->getQuery();
        return $query->get();
    }

    protected function getQuery()
    {
        $modelClass = $this->getModelClass();
        
        if (!$modelClass) {
            throw new \Exception('Model class not defined in export class');
        }
        
        $relations = $this->getRelations();

        if (!empty($relations)) {
            return $modelClass::with($relations);
        }

        return $modelClass::query();
    }

    protected function getRelations(): array
    {
        return [];
    }

    public function headings(): array
    {
        return array_map(fn($col) => $col['label'], $this->columns);
    }

    public function map($record): array
    {
        $mapped = [];

        foreach ($this->columns as $column) {
            $value = $this->getColumnValue($record, $column);
            $mapped[] = $this->formatValue($value, $column);
        }

        return $mapped;
    }

    protected function getColumnValue($record, $column)
    {
        $name = $column['name'];

        if (strpos($name, '.') !== false) {
            $parts = explode('.', $name);
            $value = $record;
            foreach ($parts as $part) {
                $value = $value->{$part} ?? null;
            }
            return $value;
        }

        if (isset($column['type']) && $column['type'] === 'relationship') {
            return $record->{$name} ? $record->{$name}->{$column['relation_field'] ?? 'libelle'} : null;
        }

        return $record->{$name} ?? null;
    }

    protected function formatValue($value, $column)
    {
        if ($value === null) {
            return '';
        }

        if (isset($column['type'])) {
            switch ($column['type']) {
                case 'date':
                    return $value instanceof \DateTime ? $value->format('d/m/Y') : $value;
                case 'datetime':
                    return $value instanceof \DateTime ? $value->format('d/m/Y H:i') : $value;
                case 'boolean':
                    return $value ? 'Oui' : 'Non';
                case 'numeric':
                    return is_numeric($value) ? (float) $value : $value;
            }
        }

        return $value;
    }

    public function styles(Worksheet $sheet)
    {
        $columnCount = count($this->columns);
        $headerRange = 'A1:' . $this->getColumnLetter($columnCount) . '1';
        $dataRange = 'A2:' . $this->getColumnLetter($columnCount) . ($sheet->getHighestRow());

        return [
            $headerRange => [
                'font' => [
                    'bold' => true,
                    'size' => 12,
                    'color' => ['rgb' => 'FFFFFF'],
                ],
                'fill' => [
                    'fillType' => Fill::FILL_SOLID,
                    'startColor' => ['rgb' => '4472C4'],
                ],
                'alignment' => [
                    'horizontal' => Alignment::HORIZONTAL_CENTER,
                    'vertical' => Alignment::VERTICAL_CENTER,
                ],
                'borders' => [
                    'allBorders' => [
                        'borderStyle' => Border::BORDER_THIN,
                        'color' => ['rgb' => '000000'],
                    ],
                ],
            ],
            $dataRange => [
                'borders' => [
                    'allBorders' => [
                        'borderStyle' => Border::BORDER_THIN,
                        'color' => ['rgb' => 'DDDDDD'],
                    ],
                ],
            ],
        ];
    }

    public function columnFormats(): array
    {
        $formats = [];

        foreach ($this->columns as $index => $column) {
            $columnLetter = $this->getColumnLetter($index + 1);

            if (isset($column['type'])) {
                switch ($column['type']) {
                    case 'numeric':
                        $formats[$columnLetter] = NumberFormat::FORMAT_NUMBER_00;
                        break;
                    case 'date':
                        $formats[$columnLetter] = NumberFormat::FORMAT_DATE_DDMMYYYY;
                        break;
                    case 'datetime':
                        $formats[$columnLetter] = NumberFormat::FORMAT_DATE_DATETIME;
                        break;
                    case 'email':
                        $formats[$columnLetter] = NumberFormat::FORMAT_TEXT;
                        break;
                }
            }
        }

        return $formats;
    }

    public function title(): string
    {
        return $this->title;
    }

    protected function applyFilters($query)
    {
        foreach ($this->filters as $filter => $value) {
            if (!empty($value)) {
                $query = $this->applyFilter($query, $filter, $value);
            }
        }

        return $query;
    }

    protected function applyFilter($query, $filter, $value)
    {
        switch ($filter) {
            case 'wilaya':
                return $query->whereHas('etablissement', function ($q) use ($value) {
                    $q->where('wilaya_id', $value);
                });
            case 'etablissement':
                return $query->where('etablissement_id', $value);
            case 'pole':
                return $query->where('pole_id', $value);
            case 'annee':
                return $query->where('annee_id', $value);
            case 'date_debut':
                return $query->where('created_at', '>=', $value);
            case 'date_fin':
                return $query->where('created_at', '<=', $value);
            default:
                return $query->where($filter, $value);
        }
    }

    protected function getColumnLetter($index)
    {
        $letter = '';
        while ($index > 0) {
            $index--;
            $letter = chr(65 + ($index % 26)) . $letter;
            $index = floor($index / 26);
        }
        return $letter;
    }

    protected function getModelClass()
    {
        return null;
    }

    protected function logExport($filename, $count)
    {
        Log::info('Excel export completed', [
            'filename' => $filename,
            'record_count' => $count,
            'filters' => $this->filters,
        ]);
    }
}
