<?php

namespace App\DataTables;

use App\DAL\Studies\WorklistFactory;
use App\Models\Study;
use App\Models\User;
use App\Services\ACL\WorklistButton;
use App\Services\ACL\WorklistColumn;
use App\Services\ACL\WorklistGuard;
use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Closure;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Str;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Html\SearchPane;
use Yajra\DataTables\Services\DataTable;

class WorklistDataTable extends DataTable
{
    const DATE_FORMAT = 'd.m.Y H:i';

    private static function renderDateColumn(Carbon|CarbonImmutable|null $dt): ?string
    {
        if ($dt === null) {
            return null;
        }

        return Blade::render(
            'staff.worklist.partials._multi-value-cell',
            [
                'title' => $dt->format(self::DATE_FORMAT),
                'subtitle' => $dt->diffForHumans(),
            ]
        );
    }

    public function dataTable(QueryBuilder $query): EloquentDataTable
    {
        $data_table = new EloquentDataTable($query);
        $rawColumns = [
            'priority_icon',
            'report_status_led',
        ];
        foreach ($this->renderCustomColumns() as $column => $content) {
            $data_table->addColumn($column, $content);
            $rawColumns[] = $column;
        }

        $data_table
            ->orderColumn(WorklistColumn::PatientName->value, sprintf('%s $1', WorklistColumn::PatientName->value))
            ->rawColumns($rawColumns)
            ->setRowId('id');

        return $data_table;
    }

    /**
     * Get the query source of dataTable.
     */
    public function query(Study $model): QueryBuilder
    {
        return WorklistFactory::getLister()->query();
        // return $model->newQuery();
    }

    /**
     * Optional method if you want to use the html builder.
     */
    public function html(): HtmlBuilder
    {
        return $this->builder()
            ->setTableId('worklist-table')
            ->columns($this->getColumns())
            ->minifiedAjax()
            ->searchPanes(SearchPane::make(['show' => true, 'hideCount' => true]))
            ->parameters(
                [
                    // 'dom' => 'Pfrtip',
                    // 'dom' => 'Bfrtip',
                    'buttons' => [
                        'searchPanes',
                        'excel',
                        // 'csv',
                        // 'pdf',
                        // 'print',
                        // 'reset',
                        // 'reload',
                    ],
                    'order' => [
                        [0, 'desc'],
                        [8, 'desc'],
                    ],
                ])
            // ->selectStyleSingle()
            ->pageLength(15)
            ->lengthMenu([15, 25, 50, 100, 250]);
    }

    /**
     * Get the dataTable columns definition.
     */
    public function getColumns(): array
    {
        $columns = [];
        foreach (WorklistGuard::worklistColumns() as $col) {
            switch ($col) {
                case WorklistColumn::Priority:
                    $columns[] = Column::make($col->value)
                        ->searchable(false)
                        ->hidden();
                    $columns[] = Column::make('priority_icon')
                        ->searchable(false)
                        ->orderable(false)
                        ->addClass('text-center')
                        ->width('20px')
                        ->title('');
                    break;
                case WorklistColumn::ReportStatus:
                    $columns[] = Column::make($col->value)
                        ->searchable(false)
                        ->hidden();
                    $columns[] = Column::make('report_status_led')
                        ->searchable(false)
                        ->orderable(false)
                        ->addClass('text-center')
                        ->width('20px')
                        ->title('');
                    break;
                case WorklistColumn::History:
                    $columns[] = Column::make($col->value)
                        ->searchable(false)
                        ->orderable(false)
                        ->addClass('text-center')
                        ->width('20px')
                        ->title('');
                    break;
                case WorklistColumn::PatientSexAge:
                    $columns[] = Column::make($col->value)
                        ->searchable(false)
                        ->orderable(false)
                        ->addClass('text-center')
                        ->title('Age');
                    break;
                case WorklistColumn::StudyDate:
                    $columns[] = Column::make($col->value)->searchable(false)->title('Scan Dt');
                    break;
                case WorklistColumn::ReceiveDate:
                    $columns[] = Column::make($col->value)->searchable(false)->title('Received');
                    break;
                case WorklistColumn::ReportDate:
                    $columns[] = Column::make($col->value)->searchable(false)->title('Read At');
                    break;
                case WorklistColumn::AssignedPhysician:
                    $columns[] = Column::make($col->value)
                        ->searchable(false)
                        ->title('Assigned');
                    break;
                case WorklistColumn::ReadingPhysician:
                    $columns[] = Column::make($col->value)
                        ->searchable(false)
                        ->title('Read By');
                    break;
                case WorklistColumn::ActionButtons:
                case WorklistColumn::ViewerButtons:
                case WorklistColumn::ReportButtons:
                    $columns[] = Column::computed($col->value)
                        ->searchable(false)
                        ->orderable(false)
                        ->exportable(false)
                        ->printable(false)
                        ->width(60)
                        ->addClass('text-center')
                        ->title('');
                    break;
                default:
                    $columns[] = Column::make($col->value)->title(Str::title($col->value));
                    break;
            }
        }

        return $columns;
    }

    /**
     * Get the filename for export.
     */
    protected function filename(): string
    {
        $parts = [
            config('app.name'),
            'worklist',
            date('YmdHi'),
        ];

        return Str::slug(implode(' ', $parts), '_');
    }

    private function physicianColumn(?User $user, Carbon|CarbonImmutable|null $dt): ?string
    {
        if ($user === null) {
            return null;
        }

        return Blade::render('staff.worklist.partials._radiologist-listing',
            [
                'avatar_url' => $user->avatar(),
                'name' => $user->display_name,
                'time' => $dt?->diffForHumans() ?? '~',
            ]
        );
    }

    /**
     * @return array<string, Closure>
     */
    private function renderCustomColumns(): array
    {
        $columns = [];

        foreach (WorklistGuard::worklistColumns() as $col) {
            switch ($col) {
                case WorklistColumn::PatientName:
                    $columns[$col->value] = fn (Study $study) => $study->sanitizedPatientName();
                    break;
                case WorklistColumn::StudyDescription:
                    $columns[$col->value] = fn (Study $study) => $study->sanitizedStudyDescription();
                    break;
                case WorklistColumn::AssignedPhysician:
                    $columns[$col->value] = fn (Study $study) => $this->physicianColumn(null, $study->assigned_at);
                    break;
                case WorklistColumn::ReadingPhysician:
                    $columns[$col->value] = fn (Study $study) => $this->physicianColumn($study->readingPhysician, $study->read_at);
                    break;
                case WorklistColumn::Series:
                    $columns[$col->value] = fn (Study $study) => Blade::render(
                        'staff.worklist.partials._multi-value-cell',
                        [
                            'title' => $study->numInstances(),
                            'subtitle' => human_filesize($study->disk_size),
                        ]
                    );
                    break;
                case WorklistColumn::StudyDate:
                case WorklistColumn::ReceiveDate:
                case WorklistColumn::ReportDate:
                case WorklistColumn::AssignDate:
                case WorklistColumn::AuthorizeDate:
                case WorklistColumn::ArchiveDate:
                    $columns[$col->value] = fn (Study $study) => self::renderDateColumn($study->{$col->value});
                    break;
                case WorklistColumn::History:
                    $columns[$col->value] = fn (Study $study) => sprintf('
   <a href="#" data-id="%s" class="btn btn-sm btn-outline-light show-attach">
    <i class="fa-light fa-file-prescription %s"></i>
    </a>
',
                        $study->hash,
                        ($study->body_part_examined) ? 'text-muted' : 'text-primary');
                    break;
                case WorklistColumn::ActionButtons:
                    $columns[$col->value] = fn (Study $study) => $this->generateActionButtons($study);
                    break;
                case WorklistColumn::ViewerButtons:
                    $columns[$col->value] = fn (Study $study) => $this->generateViewerButtons($study);
                    break;
                case WorklistColumn::ReportButtons:
                    $columns[$col->value] = fn (Study $study) => $this->generateReportingButtons($study);
                    break;
            }
        }

        return $columns;
    }

    private function generateReportingButtons(Study $study): string
    {
        if (me()->isRadiologist() && $study->canEditReport() && ! $study->hasReports()) {
            // fresh untouched study, can edit report: take the rad directly to the edit page
            return '<a href="' . route('staff.report.create', $study->hash) . '" target="_blank" class="btn btn-sm btn-outline-light"><i class="fa-light fa-edit"></i></a>';
        }

        return $this->renderButton($study->hash, 'fa-eye', 'show-reports btn-outline', 'R');
    }

    private function renderButton(string $data_id, string $fa_icon, string $data_class, string $text, string $url = '#', bool $blank = false): string
    {
        return Blade::render('staff.worklist.partials._column-button',
            [
                'data_id' => $data_id,
                'url' => $url,
                'fa_icon' => $fa_icon,
                'data_class' => $data_class,
                'text' => $text,
                'blank' => $blank,
            ]
        );
    }

    private function generateViewerButtons(Study $study): string
    {
        $btns = [];
        $btns[] = $this->renderButton($study->hash, 'fa-eye', 'btn-outline', '', route('viewer.ohif', $study->hash), true);
        $btns[] = Blade::render('staff.worklist.partials._dropdown-menu',
            [
                'items' => [
                    [
                        'url' => route('viewer.stone', $study->hash),
                        'text' => 'Stone',
                        'blank' => true,
                        'icon' => 'fa-circle-info',
                    ],
                ],
            ]
        );

        return implode("\r", $btns);
    }

    private function generateActionButtons(Study $study): string
    {
        $btns = [];
        foreach (WorklistGuard::worklistButtons() as $button) {
            switch ($button) {
                case WorklistButton::StudyMetadata:
                    $btns[] = $this->renderButton($study->hash, 'fa-circle-info', 'showStudy btn-outline-facebook', 'Info');
                    break;
                case WorklistButton::History:
                    $btns[] = $this->renderButton($study->hash, 'fa-pen-to-square', 'btn-outline-primary', 'Edit', route('staff.history.edit', $study->hash));
                    break;
                case WorklistButton::Notes:
                    $btns[] = $this->renderButton($study->hash, 'fa-user-doctor', 'btn-outline-youtube show-assign', 'Assign');
                    break;
                case WorklistButton::Attachment:
                    // $btns[] = $this->renderButton($study->hash, 'fa-trash', 'btn-danger archive-study', 'Archive');
                    break;
            }
        }

        return implode("\r", $btns);
    }
}