<?php

declare(strict_types=1);

namespace Autogedal\PromoRules\Model;

use Autogedal\PromoRules\Api\Data\RuleUsageInterface;
use Autogedal\PromoRules\Api\RuleUsageRepositoryInterface;
use Autogedal\PromoRules\Model\ResourceModel\RuleUsage as RuleUsageResource;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Exception\CouldNotDeleteException;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\NoSuchEntityException;

/**
 * Default repository for promo-rule usage persistence.
 */
class RuleUsageRepository implements RuleUsageRepositoryInterface
{
    public function __construct(
        private readonly RuleUsageResource $resource,
        private readonly RuleUsageFactory $ruleUsageFactory,
        private readonly ResourceConnection $resourceConnection
    ) {
    }

    public function save(RuleUsageInterface $ruleUsage): RuleUsageInterface
    {
        try {
            $this->resource->save($ruleUsage);
        } catch (\Throwable $exception) {
            throw new CouldNotSaveException(
                __('Unable to save promo rule usage.'),
                $exception
            );
        }

        return $ruleUsage;
    }

    public function getByRuleIdAndEmail(int $ruleId, string $normalizedEmail): RuleUsageInterface
    {
        $email = strtolower(trim($normalizedEmail));
        $connection = $this->resourceConnection->getConnection();
        $tableName = $this->resourceConnection->getTableName('autogedal_promo_rule_usage');

        $select = $connection->select()
            ->from($tableName)
            ->where(RuleUsageInterface::RULE_ID . ' = ?', $ruleId)
            ->where(RuleUsageInterface::NORMALIZED_EMAIL . ' = ?', $email)
            ->limit(1);

        $row = $connection->fetchRow($select);
        if ($row === false && $email !== $normalizedEmail) {
            $select = $connection->select()
                ->from($tableName)
                ->where(RuleUsageInterface::RULE_ID . ' = ?', $ruleId)
                ->where(RuleUsageInterface::NORMALIZED_EMAIL . ' = ?', $normalizedEmail)
                ->limit(1);
            $row = $connection->fetchRow($select);
        }

        if ($row === false) {
            throw new NoSuchEntityException(
                __('Promo rule usage not found for rule ID %1 and email %2.', $ruleId, $normalizedEmail)
            );
        }

        $ruleUsage = $this->ruleUsageFactory->create();
        $ruleUsage->setData($row);
        return $ruleUsage;
    }

    public function delete(RuleUsageInterface $ruleUsage): bool
    {
        try {
            $this->resource->delete($ruleUsage);
        } catch (\Throwable $exception) {
            throw new CouldNotDeleteException(
                __('Unable to delete promo rule usage.'),
                $exception
            );
        }

        return true;
    }

    public function deleteById(int $usageId): bool
    {
        $ruleUsage = $this->ruleUsageFactory->create();
        $this->resource->load($ruleUsage, $usageId);

        if ($ruleUsage->getUsageId() === null) {
            throw new NoSuchEntityException(
                __('Promo rule usage not found for usage ID %1.', $usageId)
            );
        }

        return $this->delete($ruleUsage);
    }
}
