<?php

declare(strict_types=1);

namespace App\Repositories;

use Core\Repository;

class HouseholdRepository extends Repository
{
    protected string $table      = 'households';
    protected string $primaryKey = 'id';

    public function countAll(string $search = '', string $territoryId = '', string $doNotCall = ''): int
    {
        [$sql, $params] = $this->buildFilterQuery(
            'SELECT COUNT(*) AS n FROM households h
             JOIN territories t ON t.id = h.territory_id',
            $search, $territoryId, $doNotCall
        );

        $row = $this->database->first($sql, $params);
        return (int) ($row['n'] ?? 0);
    }

    /** @return list<array<string,mixed>> */
    public function findPaged(int $page, int $perPage, string $search = '', string $territoryId = '', string $doNotCall = ''): array
    {
        $offset = ($page - 1) * $perPage;

        [$where, $params] = $this->buildFilterQuery(
            'SELECT h.*, t.name AS territory_name FROM households h
             JOIN territories t ON t.id = h.territory_id',
            $search, $territoryId, $doNotCall
        );

        return $this->database->query(
            $where . ' ORDER BY t.name ASC, h.street_name ASC, h.street_number ASC
              LIMIT :limit OFFSET :offset',
            array_merge($params, ['limit' => $perPage, 'offset' => $offset])
        );
    }

    /** @return list<array<string,mixed>> */
    public function findAllByTerritory(int|string $territoryId): array
    {
        return $this->database->query(
            'SELECT * FROM households WHERE territory_id = :id
             ORDER BY street_name ASC, street_number ASC',
            ['id' => $territoryId]
        );
    }

    /** @return list<array<string,mixed>> */
    public function findAllByTerritories(array $territoryIds): array
    {
        if (empty($territoryIds)) {
            return [];
        }

        $placeholders = implode(',', array_fill(0, count($territoryIds), '?'));

        return $this->database->query(
            "SELECT h.*, t.name AS territory_name
             FROM households h
             JOIN territories t ON t.id = h.territory_id
             WHERE h.territory_id IN ({$placeholders})
             ORDER BY t.name ASC, h.street_name ASC, h.street_number ASC",
            array_values($territoryIds)
        );
    }

    public function findWithTerritory(int|string $id): ?array
    {
        return $this->database->first(
            'SELECT h.*, t.name AS territory_name
             FROM households h
             JOIN territories t ON t.id = h.territory_id
             WHERE h.id = :id',
            ['id' => $id]
        );
    }

    /** @return array{string, array<string,mixed>} */
    private function buildFilterQuery(string $base, string $search, string $territoryId, string $doNotCall): array
    {
        $conditions = [];
        $params     = [];

        if ($search !== '') {
            $conditions[] = '(h.address LIKE :s OR h.street_name LIKE :s)';
            $params['s']  = '%' . $search . '%';
        }

        if ($territoryId !== '') {
            $conditions[]          = 'h.territory_id = :tid';
            $params['tid']         = $territoryId;
        }

        if ($doNotCall === '1') {
            $conditions[] = 'h.do_not_call = 1';
        } elseif ($doNotCall === '0') {
            $conditions[] = 'h.do_not_call = 0';
        }

        $sql = $base;
        if (!empty($conditions)) {
            $sql .= ' WHERE ' . implode(' AND ', $conditions);
        }

        return [$sql, $params];
    }
}
