<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
 * Phase 3 of the tenant-marking series: doctor_secretaries kept the tenant as
 * owner_type plus a nullable clinic_id, and its unique key covered only
 * (doctor_id, secretary_id, owner_type). With clinic_id outside the key, the
 * same secretary could not be assigned to the same doctor in two clinics — the
 * second row collided on owner_type = 'clinic'. Folding the pair into the key
 * fixes that, and is the one deliberate behaviour change in this series.
 *
 * Statements run through $this->connection so the guards can sit between the
 * backfill and the NOT NULL change; addSql() would defer them to the end.
 */
final class Version20260728080516 extends AbstractMigration
{
    public function getDescription(): string
    {
        return 'Replace doctor_secretaries.owner_type with the shared tenant pair and widen its unique key';
    }

    public function up(Schema $schema): void
    {
        $this->connection->executeStatement(
            'ALTER TABLE doctor_secretaries ADD entity_type VARCHAR(10) NULL, ADD entity_id INT NULL'
        );

        // A row claiming the clinic environment without a clinic is data we cannot
        // interpret; stop and let a human decide rather than guessing an owner.
        $broken = $this->connection->fetchFirstColumn(
            "SELECT id FROM doctor_secretaries WHERE owner_type = 'clinic' AND clinic_id IS NULL"
        );
        $this->abortIf(
            $broken !== [],
            'Inconsistent doctor_secretaries rows (owner_type=clinic, clinic_id NULL): ' . implode(',', $broken)
        );

        $this->connection->executeStatement(
            "UPDATE doctor_secretaries
             SET entity_type = owner_type,
                 entity_id   = IF(owner_type = 'clinic', clinic_id, doctor_id)"
        );

        $remaining = (int) $this->connection->fetchOne(
            'SELECT COUNT(*) FROM doctor_secretaries WHERE entity_type IS NULL OR entity_id IS NULL'
        );
        $this->abortIf($remaining > 0, "Backfill left {$remaining} doctor_secretaries rows without a tenant.");

        $this->connection->executeStatement(
            'ALTER TABLE doctor_secretaries MODIFY entity_type VARCHAR(10) NOT NULL, MODIFY entity_id INT NOT NULL'
        );

        // Replacement key first, so the table is never without uniqueness cover.
        $this->connection->executeStatement(
            'CREATE UNIQUE INDEX uniq_doctor_secretary_scope
             ON doctor_secretaries (doctor_id, secretary_id, entity_type, entity_id)'
        );
        $this->connection->executeStatement('DROP INDEX idx_doctor_secretary_scope ON doctor_secretaries');
        $this->connection->executeStatement('ALTER TABLE doctor_secretaries DROP owner_type');
    }

    public function down(Schema $schema): void
    {
        $this->addSql("ALTER TABLE doctor_secretaries ADD owner_type VARCHAR(10) DEFAULT 'doctor' NOT NULL");
        $this->addSql('UPDATE doctor_secretaries SET owner_type = entity_type');
        $this->addSql('CREATE UNIQUE INDEX idx_doctor_secretary_scope ON doctor_secretaries (doctor_id, secretary_id, owner_type)');
        $this->addSql('DROP INDEX uniq_doctor_secretary_scope ON doctor_secretaries');
        $this->addSql('ALTER TABLE doctor_secretaries DROP entity_type, DROP entity_id');
    }

    /** DDL on MariaDB commits implicitly; wrapping up() in a transaction would be a lie. */
    public function isTransactional(): bool
    {
        return false;
    }
}
