<?php

declare(strict_types=1);

namespace OCA\Mitgliederverwaltung\Db;

use OCA\Mitgliederverwaltung\Db\PlatformHelper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;

/**
 * Mapper for the oc_mv_lager table.
 *
 * Part of Issue #54.
 *
 * @extends QBMapper<Lager>
 */
class LagerMapper extends QBMapper {

    public function __construct(IDBConnection $db) {
        parent::__construct($db, 'mv_lager', Lager::class);
    }

    /**
     * @throws DoesNotExistException
     * @throws MultipleObjectsReturnedException
     * @throws Exception
     */
    public function findById(int $id): Lager {
        $qb = $this->db->getQueryBuilder();
        $qb->select('*')
            ->from($this->getTableName())
            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
        return $this->findEntity($qb);
    }

    /**
     * @return Lager[]
     * @throws Exception
     */
    public function findAll(?int $limit = null, ?int $offset = null): array {
        $qb = $this->db->getQueryBuilder();
        $qb->select('*')
            ->from($this->getTableName())
            ->orderBy('startdatum', 'DESC');

        if ($limit !== null) {
            $qb->setMaxResults($limit);
        }
        if ($offset !== null) {
            $qb->setFirstResult($offset);
        }

        return $this->findEntities($qb);
    }

    /**
     * Find camps by year (startdatum in given year).
     * Uses platform-aware year extraction instead of LIKE on date columns.
     *
     * Updated for Issue #192 (database portability).
     *
     * @return Lager[]
     * @throws Exception
     */
    public function findByYear(int $year): array {
        $qb = $this->db->getQueryBuilder();
        $yearExpr = PlatformHelper::getYearExpression($this->db, 'startdatum');

        $qb->select('*')
            ->from($this->getTableName())
            ->where(
                $qb->expr()->eq(
                    $qb->createFunction($yearExpr),
                    $qb->createNamedParameter($year, IQueryBuilder::PARAM_INT)
                )
            )
            ->orderBy('startdatum', 'ASC');

        return $this->findEntities($qb);
    }

    /**
     * Find camps that include a specific Stufe.
     *
     * @return Lager[]
     * @throws Exception
     */
    public function findByStufe(int $stufeId): array {
        $qb = $this->db->getQueryBuilder();
        $qb->select('l.*')
            ->from($this->getTableName(), 'l')
            ->innerJoin('l', 'mv_lager_stufen', 'ls', $qb->expr()->eq('l.id', 'ls.lager_id'))
            ->where($qb->expr()->eq('ls.stufe_id', $qb->createNamedParameter($stufeId, IQueryBuilder::PARAM_INT)))
            ->orderBy('l.startdatum', 'DESC');

        return $this->findEntities($qb);
    }
}
