<?php

namespace idoit\Module\SyneticsJdisc\Graphql\Query;

use GraphQL\Query;
use GraphQL\RawObject;
use GraphQL\Results;
use idoit\Module\SyneticsJdisc\Controller\Table\DeviceListSearchParams;
use idoit\Module\SyneticsJdisc\Graphql\AbstractGraphql;
use idoit\Module\SyneticsJdisc\Graphql\ResponseInterface;

// example:
//
// $connector = Connector::instance($serverId);
// $connector->connect();
// $query = new DeviceList();
// $query->useSearch($search);
// $data = $connector->query($query);

class DeviceList extends AbstractGraphql implements ResponseInterface
{
    // value is required for sorting, retrieved from the JDisc Web UI's GraphQL requests
    private const CANONICAL_TYPE_FIELD_DESCRIPTION = 'com.jdisc.inventory.common.reporting.base.FieldDescription';

    private string $searchString = '';
    private string $ignoreCase   = 'true';
    private string $invertSearch = 'false';
    private string $sortBy       = 'Name';
    private string $sortOrder    = 'DESCENDING';
    private string $rowCount     = '1000';
    private string $start        = '0';

    /**
     * @param int $rowCount
     * @return $this
     */
    public function setRowCount(int $rowCount): self
    {
        $this->rowCount = (string) $rowCount;
        return $this;
    }

    /**
     * @param int $start
     * @return $this
     */
    public function setStart(int $start): self
    {
        $this->start = (string) $start;
        return $this;
    }

    /**
     * @return array
     */
    public function getParameters(): array
    {
        return [];
    }

    /**
     * @return array
     */
    public function getSelections(): array
    {
        return [];
    }


    /**
     * @param Results $results
     *
     * @return array
     */
    public static function getDataFromResults(Results $results): array
    {
        $data = $results->getData();
        $types = [];
        foreach ($data['lookup']['enumerationLookup']['deviceTypeEntries'] as $type) {
            $types[$type['name']] = $type;
        }
        return [
            'columns'      => $data['reporting']['tableData']['reportDescription']['columns'] ?: [],
            'rows'         => $data['reporting']['tableData']['tableData']['rows'] ?: [],
            'totalRows'    => $data['reporting']['tableData']['tableData']['totalRows'] ?: 0,
            'visibleRows'  => $data['reporting']['tableData']['tableData']['visibleRows'] ?: 0,
            'actualOffset' => $data['reporting']['tableData']['tableData']['actualOffset'] ?: 0,
            'types'        => $types,
        ];
    }

    /**
     * @return Query
     */
    public function getQuery(): Query
    {
        $canonicalType = self::CANONICAL_TYPE_FIELD_DESCRIPTION;

        return (new Query())->setSelectionSet([
            (new Query('reporting'))->setSelectionSet([
                (new Query('tableData'))
                    ->setArguments([
                        'reportConfig' => new RawObject(
                            <<<reportConfig
                            {
                                builtInReport: DEVICE_REPORT_ID,
                                expandMultilineRows: true,
                                paging: {
                                    rowCount: {$this->rowCount},
                                    start: {$this->start}
                                }
                                type: Table,
                                sortConfiguration: [
                                    {
                                        sortBy: {
                                            canonicalType: "{$canonicalType}",
                                            fieldId: "{$this->sortBy}",
                                        },
                                        sortOrder: {$this->sortOrder}
                                    }
                                ],
                                searchConfig: {
                                    searchString: "{$this->searchString}",
                                    ignoreCase: {$this->ignoreCase},
                                    invertSearch: {$this->invertSearch}
                                }
                            }
                            reportConfig
                        )
                    ])
                    ->setSelectionSet([
                        (new Query('reportDescription'))
                            ->setSelectionSet([
                                (new Query('columns'))
                                    ->setSelectionSet([
                                        'field',
                                        'isVisible',
                                        'isSortable',
                                        'isSticky',
                                        (new Query('fieldDescription'))
                                            ->setSelectionSet([
                                                'fieldId',
                                                'columnHeader',
                                                'valueType',
                                                'webFieldWidth',
                                            ]),
                                    ])
                            ]),
                        (new Query('tableData'))
                            ->setSelectionSet([
                                'rows',
                                'totalRows',
                                'visibleRows',
                                'actualOffset',
                            ]),
                    ])
            ]),
            (new Query('lookup'))->setSelectionSet([
                (new Query('enumerationLookup'))->setSelectionSet([
                    (new Query('deviceTypeEntries'))->setSelectionSet([
                        'code',
                        'displayName',
                        'name',
                    ])
                ])
            ]),
        ]);
    }

    public function useSearch(DeviceListSearchParams $search): void
    {
        $this->searchString = $search->getSearchTerm() ?? '';
        $this->ignoreCase   = $search->isIgnoreCase() ? 'true' : 'false';
        $this->invertSearch = $search->isInvertSearch() ? 'true' : 'false';
        $this->sortBy       = $search->getSort()?->getId() ?? 'Name';
        $this->sortOrder    = $search->getSort()?->isDesc() ? 'DESCENDING' : 'ASCENDING';
        $this->rowCount     = $search->getPerPage() ?? '1000';
        $this->start        = $search->getOffset() ?? '0';
    }
}
