<?php

declare(strict_types=1);

namespace App\Core;

class FileStore
{
    private string $collection;

    public function __construct(private string $file)
    {
        $this->collection = pathinfo($this->file, PATHINFO_FILENAME);

        if (Database::enabled()) {
            Database::ensureSchema();
            return;
        }

        $directory = dirname($this->file);

        if (!is_dir($directory)) {
            mkdir($directory, 0775, true);
        }

        if (!file_exists($this->file)) {
            file_put_contents($this->file, json_encode([], JSON_PRETTY_PRINT));
        }
    }

    public function all(): array
    {
        if (Database::enabled()) {
            $statement = Database::pdo()->prepare(
                'SELECT record_id, payload FROM app_records WHERE collection = :collection ORDER BY record_id ASC'
            );
            $statement->execute(['collection' => $this->collection]);

            $records = [];
            foreach ($statement->fetchAll() as $row) {
                $record = json_decode((string) $row['payload'], true);
                if (is_array($record)) {
                    $record['id'] = $record['id'] ?? (int) $row['record_id'];
                    $records[] = $record;
                }
            }

            return $records;
        }

        $content = file_get_contents($this->file);
        $data = json_decode($content ?: '[]', true);

        return is_array($data) ? $data : [];
    }

    public function save(array $records): void
    {
        if (Database::enabled()) {
            $pdo = Database::pdo();
            $pdo->beginTransaction();

            try {
                $delete = $pdo->prepare('DELETE FROM app_records WHERE collection = :collection');
                $delete->execute(['collection' => $this->collection]);

                $insert = $pdo->prepare(
                    'INSERT INTO app_records (collection, record_id, payload)
                     VALUES (:collection, :record_id, :payload)'
                );

                foreach (array_values($records) as $index => $record) {
                    $recordId = (int) ($record['id'] ?? ($index + 1));
                    if ($recordId <= 0) {
                        $recordId = $index + 1;
                    }

                    $record['id'] = $recordId;
                    $insert->execute([
                        'collection' => $this->collection,
                        'record_id' => $recordId,
                        'payload' => json_encode($record, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                    ]);
                }

                $pdo->commit();
            } catch (\Throwable $exception) {
                $pdo->rollBack();
                throw $exception;
            }

            return;
        }

        file_put_contents(
            $this->file,
            json_encode(array_values($records), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE),
            LOCK_EX
        );
    }

    public function insert(array $record): array
    {
        if (Database::enabled()) {
            $pdo = Database::pdo();
            $statement = $pdo->prepare('SELECT MAX(record_id) FROM app_records WHERE collection = :collection');
            $statement->execute(['collection' => $this->collection]);
            $record['id'] = ((int) $statement->fetchColumn()) + 1;

            $insert = $pdo->prepare(
                'INSERT INTO app_records (collection, record_id, payload)
                 VALUES (:collection, :record_id, :payload)'
            );
            $insert->execute([
                'collection' => $this->collection,
                'record_id' => (int) $record['id'],
                'payload' => json_encode($record, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
            ]);

            return $record;
        }

        $records = $this->all();
        $record['id'] = $this->nextId($records);
        $records[] = $record;
        $this->save($records);

        return $record;
    }

    private function nextId(array $records): int
    {
        $ids = array_column($records, 'id');

        return $ids ? max($ids) + 1 : 1;
    }
}
