<?php

namespace Velis\Db\QueryBuilder;

/**
 * Class used to resolve conflicts in params and SQL
 * @author Jakub Szczugieł <jakub.szczugiel@velistech.com>
 */
class ConflictsResolver
{
    /**
     * Fix conflicts in params, based on conflicts mapping
     * @param array<string, mixed> $params
     * @param array<string, string> $conflicts Old keys => new keys mapping
     * @return array<string, mixed> Fixed params
     */
    public function fixParams(array $params, array $conflicts): array
    {
        $newParams = [];
        foreach ($params as $key => $param) {
            $newKey = $conflicts[$key] ?? $key;
            $newParams[$newKey] = $param;
        }

        return $newParams;
    }

    /**
     * Fix conflicts in SQL, based on conflicts mapping
     * @param array<string, string> $conflicts Old keys => new keys mapping
     * @return string Fixed SQL
     */
    public function fixSql(string $sql, array $conflicts): string
    {
        $keys = array_keys($conflicts);
        $newKeys = array_values($conflicts);

        return $this->replaceKeys($sql, $keys, $newKeys);
    }

    /**
     * Return mapping for conflicted keys
     * @param array<string, mixed> $oldParams
     * @param array<string, mixed> $newParams
     * @return array<string, string> Old keys => new keys
     */
    public function getConflicts(array $oldParams, array $newParams): array
    {
        $conflicts = [];
        foreach ($newParams as $key => $param) {
            $conflictKey = 1;
            $newKey = $key;

            while (array_key_exists($newKey, $oldParams) && $oldParams[$newKey] !== $param) {
                $newKey = $key . '_' . $conflictKey++;
            }

            if ($key != $newKey) {
                $conflicts[$key] = $newKey;
            }
        }

        return $conflicts;
    }

    private function replaceKeys(string $sql, array $keys, array $newKeys): string
    {
        foreach ($keys as $i => $key) {
            $sql = str_replace(":{$key}", ":{$newKeys[$i]}", $sql);
        }

        return $sql;
    }
}
