<?php

namespace Velis\Db;

use ReflectionException;
use ReflectionMethod;

/**
 * @author Jan Małysiak <jan.malysiak@velis.pl>
 */
class ClassMetadata
{
    /**
     * @var string
     */
    private $tableName;

    /**
     * @var string|string[]
     */
    private $primaryKeyField;

    /**
     * @var ?string
     */
    private $primaryKeySeq;

    /**
     * @var string
     */
    private $repositoryClass;

    /**
     * @param string $entityClass
     * @throws ReflectionException
     */
    public function __construct(string $entityClass)
    {
        $instance = new $entityClass();

        $tableNameMethod = new ReflectionMethod($entityClass, '_getTableName');
        $tableNameMethod->setAccessible(true);
        $this->tableName = $tableNameMethod->invoke($instance);

        $primaryKeyFieldMethod = new ReflectionMethod($entityClass, '_getPrimaryKeyField');
        $primaryKeyFieldMethod->setAccessible(true);
        $this->primaryKeyField = $primaryKeyFieldMethod->invoke($instance);

        if (!is_array($this->primaryKeyField)) {
            $primaryKeySeqMethod = new ReflectionMethod($entityClass, '_getPrimaryKeySeq');
            $primaryKeySeqMethod->setAccessible(true);
            $this->primaryKeySeq = $primaryKeySeqMethod->invoke($instance);
        }

        $this->repositoryClass = $this->resolveRepositoryClass($entityClass);
    }

    /**
     * @param string $entityClass
     * @return string
     */
    private function resolveRepositoryClass(string $entityClass): string
    {
        $splitFqcn = explode('\\', $entityClass);
        $moduleName = array_shift($splitFqcn);
        $splitRepositoryNamespace = array_merge([$moduleName, 'Repository'], $splitFqcn);

        $repositoryFqcn = implode('\\', $splitRepositoryNamespace) . 'Repository';

        if (class_exists($repositoryFqcn)) {
            return $repositoryFqcn;
        }

        return EntityRepository::class;
    }

    /**
     * @return string
     */
    public function getTableName(): string
    {
        return $this->tableName;
    }

    /**
     * @return string|string[]
     */
    public function getPrimaryKeyField()
    {
        return $this->primaryKeyField;
    }

    /**
     * @return ?string
     */
    public function getPrimaryKeySeq()
    {
        return $this->primaryKeySeq;
    }

    /**
     * @return string
     */
    public function getRepositoryClass(): string
    {
        return $this->repositoryClass;
    }
}
