<?php declare(strict_types=1);

use PhpCsFixer\Fixer\Basic\BracesFixer;
use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
use PhpCsFixer\Fixer\Operator\NewWithBracesFixer;
use PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer;
use PhpCsFixer\Fixer\Whitespace\NoExtraBlankLinesFixer;
use PhpCsFixer\Fixer\Whitespace\NoWhitespaceInBlankLineFixer;
use SlevomatCodingStandard\Sniffs\Attributes\AttributeAndTargetSpacingSniff;
use SlevomatCodingStandard\Sniffs\Classes\ClassConstantVisibilitySniff;
use SlevomatCodingStandard\Sniffs\ControlStructures\NewWithoutParenthesesSniff;
use SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff;
use SlevomatCodingStandard\Sniffs\Namespaces\DisallowGroupUseSniff;
use SlevomatCodingStandard\Sniffs\Namespaces\MultipleUsesPerLineSniff;
use SlevomatCodingStandard\Sniffs\Namespaces\NamespaceSpacingSniff;
use SlevomatCodingStandard\Sniffs\Namespaces\ReferenceUsedNamesOnlySniff;
use SlevomatCodingStandard\Sniffs\Namespaces\UseSpacingSniff;
use SlevomatCodingStandard\Sniffs\TypeHints\DeclareStrictTypesSniff;
use SlevomatCodingStandard\Sniffs\TypeHints\UnionTypeHintFormatSniff;
use Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;

return static function (ECSConfig $c): void {
    $c->skip([
        BlankLineAfterOpeningTagFixer::class,
        NewWithBracesFixer::class,
        OrderedImportsFixer::class,
    ]);

    $c->sets([
        SetList::ARRAY,
        SetList::CLEAN_CODE,
        SetList::COMMENTS,
        SetList::COMMON,
        SetList::CONTROL_STRUCTURES,
        SetList::DOCBLOCK,
        SetList::NAMESPACES,
        SetList::PSR_12,
        SetList::SPACES,
        SetList::STRICT,
        SetList::SYMPLIFY,
    ]);

    // force visibility declaration on class constants
    $c->ruleWithConfiguration(ClassConstantVisibilitySniff::class, [
        'fixable' => true,
    ]);

    // sort all use statements
    $c->rules([
        AlphabeticallySortedUsesSniff::class,
        DisallowGroupUseSniff::class,
        MultipleUsesPerLineSniff::class,
        NamespaceSpacingSniff::class,
    ]);

    // import all namespaces, and event php core functions and classes
    $c->ruleWithConfiguration(
        ReferenceUsedNamesOnlySniff::class,
        [
            'allowFallbackGlobalConstants' => false,
            'allowFallbackGlobalFunctions' => false,
            'allowFullyQualifiedGlobalClasses' => false,
            'allowFullyQualifiedGlobalConstants' => false,
            'allowFullyQualifiedGlobalFunctions' => false,
            'allowFullyQualifiedNameForCollidingClasses' => true,
            'allowFullyQualifiedNameForCollidingConstants' => true,
            'allowFullyQualifiedNameForCollidingFunctions' => true,
            'searchAnnotations' => true,
        ]
    );

    // define newlines between use statements
    $c->ruleWithConfiguration(UseSpacingSniff::class, [
        'linesCountAfterLastUse' => 1,
        'linesCountBeforeFirstUse' => 1,
        'linesCountBetweenUseTypes' => 1,
    ]);

    // strict types declaration should be on same line as opening tag
    $c->ruleWithConfiguration(
        DeclareStrictTypesSniff::class,
        [
            'declareOnFirstLine' => true,
            'spacesCountAroundEqualsSign' => 0,
        ]
    );

    // disallow ?Foo typehint in favor of Foo|null
    $c->ruleWithConfiguration(UnionTypeHintFormatSniff::class, [
        'nullPosition' => 'last',
        'shortNullable' => 'no',
        'withSpaces' => 'no',
    ]);

    // Remove useless parentheses in new statements
    $c->rule(BracesFixer::class);
    $c->rule(NewWithoutParenthesesSniff::class);

    // do not inline short multilinestatements
    $c->ruleWithConfiguration(LineLengthFixer::class, [
        LineLengthFixer::INLINE_SHORT_LINES => false,
    ]);

    $c->ruleWithConfiguration(
        NoExtraBlankLinesFixer::class,
        [
            'tokens' => ['square_brace_block', 'return', 'extra'],
        ]
    );

    $c->rule(NoWhitespaceInBlankLineFixer::class);

    // make sure that the attribute target is on the line after the attribute
    $c->ruleWithConfiguration(AttributeAndTargetSpacingSniff::class, [
        'linesCount' => 0,
    ]);
};