<?php

namespace app\foreignone;

use app\foreignone\files\Archive;
use app\foreignone\files\ArchiveType;
use app\foreignone\files\Book;
use app\foreignone\files\Util as FilesUtil;
use app\foreignone\files\SectionType;
use engine\http\AjaxOk;
use engine\http\errors\NotFound;
use engine\http\Response;

class FilesHandler
    extends BaseHandler
{
    const int SEARCH_RESULTS_PER_PAGE = 50;
    const int SEARCH_MIN_QUERY_LENGTH = 3;

    public function GET_files(): Response {
        $collections = array_map(fn(ArchiveType $c) => new Archive($c), ArchiveType::cases());
        $books = Book::getList(section: SectionType::BOOKS_AND_ARTICLES);
        $misc = Book::getList(section: SectionType::MISC);

        $this->skin->meta->title = lang('meta_files_title');
        $this->skin->meta->description = lang('meta_files_description');
        $this->skin->title = lang('files');
        $this->skin->options->headSection = 'files';
        return $this->skin->renderPage('files_index.twig', [
            'collections' => $collections,
            'books' => $books,
            'misc' => $misc
        ]);
    }

    public function GET_folder(): Response {
        list($folder_id) = $this->input('i:folder_id');

        $parents = Book::getFolder($folder_id, with_parents: true);
        if (!$parents)
            throw new NotFound();

        if (count($parents) > 1)
            $parents = array_reverse($parents);

        $folder = $parents[count($parents)-1];
        $files = Book::getList($folder->category, $folder_id);

        $bc = [
            ['text' => lang('files'), 'url' => '/files/'],
        ];
        if ($parents) {
            for ($i = 0; $i < count($parents)-1; $i++) {
                $parent = $parents[$i];
                $bc_item = ['text' => $parent->getTitle()];
                if ($i < count($parents)-1)
                    $bc_item['url'] = $parent->getUrl();
                $bc[] = $bc_item;
            }
        }
        $bc[] = ['text' => $folder->title];

        $this->skin->meta->title = lang('meta_files_book_folder_title', $folder->getTitle());
        $this->skin->meta->description = lang('meta_files_book_folder_description', $folder->getTitle());
        $this->skin->title = lang('files').' - '.$folder->title;
        return $this->skin->renderPage('files_folder.twig', [
            'folder' => $folder,
            'bc' => $bc,
            'files' => $files
        ]);
    }

    public function GET_collection(): Response {
        list($archive, $folder_id, $query, $offset) = $this->input('collection, i:folder_id, q, i:offset');
        $archive = ArchiveType::from($archive);
        $parents = null;

        $query = trim($query);
        if (!$query)
            $query = null;

        $this->skin->exportStrings('/^files_(.*?)_collection$/');
        $this->skin->exportStrings([
            'files_search_results_count'
        ]);

        $vars = [];
        $text_excerpts = null;
        $func_prefix = $archive->value;

        if ($query !== null) {
            $files = FilesUtil::searchArchive($archive, $query, $offset, self::SEARCH_RESULTS_PER_PAGE);
            $vars += [
                'search_count' => $files['count'],
                'search_query' => $query
            ];

            $files = $files['items'];
            $query_words = array_map('mb_strtolower', preg_split('/\s+/', $query));
            $found = [];
            $result_ids = [];
            foreach ($files as $file) {
                if ($file->type == 'folder')
                    continue;
                $result_ids[] = $file->id;
                $candidates = [];
                switch ($archive) {
                    case ArchiveType::MercureDeFrance:
                        $candidates = [
                            $file->date,
                            (string)$file->issue
                        ];
                        break;
                    case ArchiveType::WilliamFriedman:
                        $candidates = [
                            mb_strtolower($file->getTitle()),
                            strtolower($file->documentId)
                        ];
                        break;
                }
                foreach ($candidates as $haystack) {
                    foreach ($query_words as $qw) {
                        if (mb_strpos($haystack, $qw) !== false) {
                            $found[$file->id] = true;
                            continue 2;
                        }
                    }
                }
            }

            $found = array_map('intval', array_keys($found));
            $not_found = array_diff($result_ids, $found);
            if (!empty($not_found))
                $text_excerpts = FilesUtil::getTextExcerpts($archive, $not_found, $query_words);

            if (isXHRRequest()) {
                return new AjaxOk(
                    [
                        ...$vars,
                        'new_offset' => $offset + count($files),
                        'html' => $this->skin->render('files_list.twig', [
                            'files' => $files,
                            'search_query' => $query,
                            'text_excerpts' => $text_excerpts
                        ])
                    ]
                );
            }
        } else {
            if (in_array($archive, [ArchiveType::WilliamFriedman, ArchiveType::Baconiana]) && $folder_id) {
                $parents = $archive->getFolderGetter()($folder_id, with_parents: true);
                if (!$parents)
                    throw new NotFound();
                if (count($parents) > 1)
                    $parents = array_reverse($parents);
            }
            $files = $archive->getListGetter()($folder_id);
        }

        $title = lang('files_'.$archive->value.'_collection');
        if ($folder_id && $parents)
            $title .= ' - '.htmlescape($parents[count($parents)-1]->getTitle());
        if ($query)
            $title .= ' - '.htmlescape($query);
        $this->skin->title = $title;

        if (!$folder_id && !$query) {
            $this->skin->meta->title = lang('4in1').' - '.lang('meta_files_collection_title', lang('files_'.$archive->value.'_collection'));
            $this->skin->meta->description = lang('meta_files_'.$archive->value.'_description');
        } else if ($query || $parents) {
            $this->skin->meta->title = lang('4in1').' - '.$title;
            $this->skin->meta->description = lang('meta_files_'.($query ? 'search' : 'folder').'_description',
                $query ?: $parents[count($parents)-1]->getTitle(),
                lang('files_'.$archive->value.'_collection'));
        }

        $bc = [
            ['text' => lang('files'), 'url' => '/files/'],
        ];
        if ($parents) {
            $bc[] = ['text' => lang('files_'.$archive->value.'_collection_short'), 'url' => "/files/{$archive->value}/"];
            for ($i = 0; $i < count($parents); $i++) {
                $parent = $parents[$i];
                $bc_item = ['text' => $parent->getTitle()];
                if ($i < count($parents)-1)
                    $bc_item['url'] = $parent->getUrl();
                $bc[] = $bc_item;
            }
        } else {
            $bc[] = ['text' => lang('files_'.$archive->value.'_collection')];
        }

        $js_params = [
            'container' => 'files_list',
            'per_page' => self::SEARCH_RESULTS_PER_PAGE,
            'min_query_length' => self::SEARCH_MIN_QUERY_LENGTH,
            'base_url' => "/files/{$archive->value}/",
            'query' => $vars['search_query'] ?? '',
            'count' => $vars['search_count'] ?? 0,
            'collection_name' => $archive->value,
            'inited_with_search' => !!($vars['search_query'] ?? "")
        ];

        $this->skin->set($vars);
        $this->skin->set([
            'collection' => $archive->value,
            'files' => $files,
            'bc' => $bc,
            'do_show_search' => empty($parents),
            'do_show_more' => ($vars['search_count'] ?? 0) > 0 && count($files) < ($vars['search_count'] ?? 0),
            'text_excerpts' => $text_excerpts,
            'js_params' => $js_params,
        ]);
        return $this->skin->renderPage('files_collection.twig');
    }
}