<?php

declare(strict_types=1);

namespace App\Modules\Administration\Repositories;

use PDO;
use RuntimeException;
use System\Contracts\DatabaseInterface;
use System\Database\QueryBuilder;

final class DynamicFormRepository
{
    private PDO $pdo;

    public function __construct(
        private QueryBuilder $query,
        DatabaseInterface $database
    ) {
        $this->pdo =
            $database->getConnection();
    }


    public function all(): array
    {
        return $this->query
            ->table('dynamic_forms')
            ->orderBy('id', 'DESC')
            ->get();
    }


    public function find(
        int $id
    ): ?array {
        return $this->query
            ->table('dynamic_forms')
            ->find($id);
    }


    public function findByCode(
        string $formCode
    ): ?array {
        return $this->query
            ->table('dynamic_forms')
            ->where(
                'form_code',
                $formCode
            )
            ->first();
    }


    public function create(
        array $data
    ): bool {
        return $this->query
            ->table('dynamic_forms')
            ->insert($data);
    }


    public function update(
        int $id,
        array $data
    ): bool {
        return $this->query
            ->table('dynamic_forms')
            ->where('id', $id)
            ->update($data);
    }


    public function hasSubmissions(
        int $formId
    ): bool {
        $statement =
            $this->pdo->prepare(
                '
                SELECT COUNT(*)
                FROM dynamic_form_submissions
                WHERE form_id = ?
                '
            );

        $statement->execute([
            $formId
        ]);

        return (int)
            $statement->fetchColumn() > 0;
    }


    public function deleteDraftForm(
        int $formId
    ): void {
        if (
            $this->pdo->inTransaction()
        ) {
            throw new RuntimeException(
                'Database transaction already active.'
            );
        }

        $this->pdo->beginTransaction();

        try {

            /*
             * Delete field options first.
             */

            $statement =
                $this->pdo->prepare(
                    '
                    DELETE o
                    FROM dynamic_form_field_options o

                    INNER JOIN dynamic_form_fields f
                        ON f.id = o.field_id

                    WHERE f.form_id = ?
                    '
                );

            $statement->execute([
                $formId
            ]);


            /*
             * Delete form fields.
             */

            $statement =
                $this->pdo->prepare(
                    '
                    DELETE FROM dynamic_form_fields
                    WHERE form_id = ?
                    '
                );

            $statement->execute([
                $formId
            ]);


            /*
             * Delete form sections.
             */

            $statement =
                $this->pdo->prepare(
                    '
                    DELETE FROM dynamic_form_sections
                    WHERE form_id = ?
                    '
                );

            $statement->execute([
                $formId
            ]);


            /*
             * Delete form.
             */

            $statement =
                $this->pdo->prepare(
                    '
                    DELETE FROM dynamic_forms
                    WHERE id = ?
                    '
                );

            $statement->execute([
                $formId
            ]);


            if (
                $statement->rowCount() !== 1
            ) {
                throw new RuntimeException(
                    'Dynamic form deletion failed.'
                );
            }


            $this->pdo->commit();

        } catch (\Throwable $exception) {

            if (
                $this->pdo->inTransaction()
            ) {
                $this->pdo->rollBack();
            }

            throw $exception;
        }
    }
}