<?php

namespace CrowdinApiClient\Api;

use CrowdinApiClient\Http\ResponseDecorator\ResponseModelListDecorator;
use CrowdinApiClient\Model\DownloadFile;
use CrowdinApiClient\Model\Glossary;
use CrowdinApiClient\Model\GlossaryConcept;
use CrowdinApiClient\Model\GlossaryConcordance;
use CrowdinApiClient\Model\GlossaryExport;
use CrowdinApiClient\Model\GlossaryImport;
use CrowdinApiClient\Model\Term;
use CrowdinApiClient\ModelCollection;

/**
 * Glossaries help to explain some specific terms or the ones often used in the project so that they can be properly and consistently translated.
 * Use API to manage glossaries or specific terms.
 * Glossary export and import are asynchronous operations and shall be completed with sequence of API methods.
 *
 * @package Crowdin\Api
 */
class GlossaryApi extends AbstractApi
{
    /**
     * List Glossaries
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.getMany API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.getMany API Documentation Enterprise
     *
     * @param array $params
     * integer $params[groupId]<br>
     * integer $params[limit]<br>
     * integer $params[offset]<br>
     * integer $params[userId]
     * @return ModelCollection
     */
    public function list(array $params = []): ModelCollection
    {
        return $this->_list('glossaries', Glossary::class, $params);
    }

    /**
     * Add Glossary
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.post API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.post API Documentation Enterprise
     *
     * @param array $params
     * string $params[name] required<br>
     * integer $params[groupId]
     * @return Glossary|null
     */
    public function create(array $params): ?Glossary
    {
        return $this->_create('glossaries', Glossary::class, $params);
    }

    /**
     * Get Glossary
     * @link https://developer.crowdin.com/api/api/#operation/api.glossaries.get API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.get API Documentation Enterprise
     *
     * @param int $glossaryId
     * @return Glossary|null
     */
    public function get(int $glossaryId): ?Glossary
    {
        return $this->_get('glossaries/' . $glossaryId, Glossary::class);
    }

    /**
     * Delete Glossary
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.delete API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.delete API Documentation Enterprise
     *
     * @param int $glossaryId
     * @return mixed
     */
    public function delete(int $glossaryId)
    {
        return $this->_delete('glossaries/' . $glossaryId);
    }

    /**
     * Edit Glossary Info
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.patch API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.patch API Documentation Enterprise
     *
     * @param Glossary $glossary
     * @return Glossary|null
     */
    public function update(Glossary $glossary): ?Glossary
    {
        return $this->_update('glossaries/' . $glossary->getId(), $glossary);
    }

    /**
     * Export Glossary
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.exports.post API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.exports.post API Documentation Enterprise
     *
     * @param int $glossaryId
     * @param string $format
     * @param array $exportFields
     * @return GlossaryExport|null
     */
    public function export(
        int $glossaryId,
        string $format = 'tbx',
        array $exportFields = []
    ): ?GlossaryExport {
        $path = sprintf('glossaries/%d/exports', $glossaryId);
        $params = [];

        if ($format !== 'tbx') {
            $params['format'] = $format;
        }

        if ($exportFields !== []) {
            $params['exportFields'] = $exportFields;
        }

        return $this->_post($path, GlossaryExport::class, $params);
    }

    /**
     * Check Glossary Export Status
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.exports.get API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.exports.get API Documentation Enterprise
     *
     * @param int $glossaryId
     * @param string $exportId
     * @return GlossaryExport|null
     */
    public function getExport(int $glossaryId, string $exportId): ?GlossaryExport
    {
        $path = sprintf('glossaries/%d/exports/%s', $glossaryId, $exportId);
        return $this->_get($path, GlossaryExport::class);
    }

    /**
     * Download Glossary
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.exports.download.download API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.exports.download.download API Documentation Enterprise
     *
     * @param int $glossaryId
     * @param string $exportId
     * @return DownloadFile|null
     */
    public function download(int $glossaryId, string $exportId): ?DownloadFile
    {
        $path = sprintf('glossaries/%d/exports/%s/download', $glossaryId, $exportId);
        return $this->_get($path, DownloadFile::class);
    }

    /**
     * Import Glossary
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.imports.post API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.imports.post API Documentation
     *
     * @param int $glossaryId
     * @param array $data
     * integer $data[storageId] required<br>
     * array $data[scheme]<br>
     * boolean $data[firstLineContainsHeader]
     * @return GlossaryImport|null
     */
    public function import(int $glossaryId, array $data): ?GlossaryImport
    {
        $path = sprintf('glossaries/%d/imports', $glossaryId);
        return $this->_post($path, GlossaryImport::class, $data);
    }

    /**
     * Check Glossary Import Status
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.imports.get API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.imports.get API Documentation Enterprise
     *
     * @param int $glossaryId
     * @param string $importId
     * @return GlossaryImport|null
     */
    public function getImport(int $glossaryId, string $importId): ?GlossaryImport
    {
        $path = sprintf('glossaries/%d/imports/%s', $glossaryId, $importId);
        return $this->_get($path, GlossaryImport::class);
    }

    /**
     * Concordance search in Glossaries
     * @link https://developer.crowdin.com/api/v2/#operation/api.projects.glossaries.concordance.post API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.glossaries.concordance.post API Documentation Enterprise
     *
     * @param int $projectId
     * @param array $data
     * string $data[sourceLanguageId]<br>
     * string $data[targetLanguageId]<br>
     * string[] $data[expressions]<br>
     * string $data[expression]<br>
     * @return ModelCollection|null
     */
    public function concordance(int $projectId, array $data): ?ModelCollection
    {
        return $this->client->apiRequest(
            'post',
            sprintf('projects/%d/glossaries/concordance', $projectId),
            new ResponseModelListDecorator(GlossaryConcordance::class),
            [
                'body' => json_encode($data),
                'headers' => $this->getHeaders(),
            ]
        );
    }

    /**
     * List Terms
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.terms.getMany API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.terms.getMany API Documentation Enterprise
     *
     * @param int $glossaryId
     * @param array $params
     * integer $params[userId]<br>
     * string $params[languageId]<br>
     * integer $params[translationOfTermId]<br>
     * integer $params[limit]<br>
     * integer $params[offset]
     * @return ModelCollection|null
     */
    public function listTerms(int $glossaryId, array $params = []): ?ModelCollection
    {
        $path = sprintf('glossaries/%d/terms', $glossaryId);
        return $this->_list($path, Term::class, $params);
    }

    /**
     * Add Term
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.terms.post API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.terms.post API Documentation Enterprise
     *
     * @param int $glossaryId
     * @param array $data
     * string $data[languageId] required<br>
     * string $data[text] required<br>
     * string $data[description]<br>
     * string $data[partOfSpeech]<br>
     * integer $data[translationOfTermId]
     * @return mixed
     */
    public function createTerm(int $glossaryId, array $data): ?Term
    {
        $path = sprintf('glossaries/%d/terms', $glossaryId);
        return $this->_create($path, Term::class, $data);
    }

    /**
     * Clear Glossary
     * @link https://developer.crowdin.com/v2/api/#operation/api.glossaries.terms.deleteMany API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.terms.deleteMany API Documentation Enterprise
     *
     * @param int $glossaryId
     * @return mixed
     */
    public function clearTerms(int $glossaryId)
    {
        $path = sprintf('glossaries/%d/terms', $glossaryId);
        return $this->_delete($path);
    }

    /**
     * Get Term Info
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.terms.get API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.terms.get API Documentation Enterprise
     *
     * @param int $glossaryId
     * @param int $termId
     * @return Term|null
     */
    public function getTerm(int $glossaryId, int $termId): ?Term
    {
        $path = sprintf('glossaries/%d/terms/%d', $glossaryId, $termId);
        return $this->_get($path, Term::class);
    }

    /**
     * Delete Term
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.terms.delete API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.terms.delete API Documentation Enterprise
     *
     * @param int $glossaryId
     * @param int $termId
     * @return mixed
     */
    public function deleteTerm(int $glossaryId, int $termId)
    {
        $path = sprintf('glossaries/%d/terms/%d', $glossaryId, $termId);
        return $this->_delete($path);
    }

    /**
     * Edit Term
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.terms.patch API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.terms.patch API Documentation Enterprise
     *
     * @param Term $term
     * @return Term|null
     */
    public function updateTerm(Term $term): ?Term
    {
        $path = sprintf('glossaries/%d/terms/%d', $term->getGlossaryId(), $term->getId());
        return $this->_update($path, $term);
    }

    /**
     * List Concepts
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.terms.getMany API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.terms.getMany API Documentation Enterprise
     */
    public function listConcepts(int $glossaryId, array $params = []): ?ModelCollection
    {
        $path = sprintf('glossaries/%d/concepts', $glossaryId);
        return $this->_list($path, GlossaryConcept::class, $params);
    }

    /**
     * Get Concept
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.concepts.get API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.concepts.get API Documentation Enterprise
     */
    public function getConcept(int $glossaryId, int $conceptId): ?GlossaryConcept
    {
        $path = sprintf('glossaries/%d/concepts/%d', $glossaryId, $conceptId);
        return $this->_get($path, GlossaryConcept::class);
    }

    /**
     * Update Concept
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.concepts.put API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.concepts.put API Documentation Enterprise
     *
     * @param array $data
     * string $data[subject]<br>
     * string $data[definition]<br>
     * bool $data[translatable]<br>
     * string $data[note]<br>
     * string $data[url]<br>
     * string $data[figure]<br>
     * array[] $data[languageDetails]<br>
     */
    public function updateConcept(int $glossaryId, int $conceptId, array $data): GlossaryConcept
    {
        $path = sprintf('glossaries/%d/concepts/%d', $glossaryId, $conceptId);
        return $this->_put($path, GlossaryConcept::class, $data);
    }

    /**
     * Delete Concept
     * @link https://developer.crowdin.com/api/v2/#operation/api.glossaries.concepts.delete API Documentation
     * @link https://developer.crowdin.com/enterprise/api/v2/#operation/api.glossaries.concepts.delete API Documentation Enterprise
     *
     * @return mixed
     */
    public function deleteConcept(int $glossaryId, int $conceptId)
    {
        $path = sprintf('glossaries/%d/concepts/%d', $glossaryId, $conceptId);
        return $this->_delete($path);
    }
}
