import { type MigrationInterface, type QueryRunner } from 'typeorm';

/**
 * Adds the "Sales Head" system role + its full permission matrix to
 * every existing tenant. Idempotent — safe to re-run; safe to run on
 * a fresh DB (no-ops if no tenants exist yet).
 *
 * Why a migration AND a SEED_ROLES entry?
 *   - SEED_ROLES (in tenant.service.ts) covers tenants onboarded
 *     AFTER this commit lands.
 *   - This migration covers tenants onboarded BEFORE — currently
 *     just the dev tenant on workzy.co, but the SQL is generic.
 *
 * Sales Head permission matrix (defaultAccess = VIEW with two EDIT
 * overrides) — kept in lockstep with SEED_ROLES in tenant.service.ts.
 * If you change one, change both, or run this migration's down + up
 * after the seed is updated.
 *
 * Per scope.md "Role-Based Dashboards" (locked 2026-05-08):
 *   - Triage queries (QUERY=edit)
 *   - Approve discount overrides (BOOKING_APPROVAL=edit)
 *   - Read-only awareness everywhere else (VIEW)
 */
export class SalesHeadRole1778100000000 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    // Step 1 — insert "Sales Head" role for each tenant that doesn't
    // already have it. is_system = true so it can't be deleted via the
    // Roles UI (governance.md: system roles are immutable in Phase 1).
    await queryRunner.query(`
      INSERT INTO roles (name, description, is_system, tenant_id, created_by, updated_by)
      SELECT
        'Sales Head',
        'Lead the sales team — triage queries, approve quotes/discounts, monitor team performance',
        true,
        t.id,
        NULL,
        NULL
      FROM tenants t
      WHERE NOT EXISTS (
        SELECT 1 FROM roles r
        WHERE r.tenant_id = t.id
          AND r.name = 'Sales Head'
          AND r.is_deleted = false
      )
    `);

    // Step 2 — for each Sales Head role row (one per tenant), insert
    // any missing permission rows. Modules + access levels are encoded
    // inline as a VALUES table so the migration is self-contained and
    // doesn't drift if the ModuleName enum changes — re-run after a new
    // module is added to top up the row, or rely on TenantService's
    // onModuleInit which already backfills missing modules per role.
    await queryRunner.query(`
      WITH sales_head_roles AS (
        SELECT id, tenant_id
        FROM roles
        WHERE name = 'Sales Head' AND is_deleted = false
      ),
      perms (module, access_level) AS (
        VALUES
          ('query',              'edit'),
          ('booking_approval',   'edit'),
          ('markup',             'view'),
          ('booking',            'view'),
          ('driver_assignment',  'view'),
          ('movement_chart',     'view'),
          ('payment_settlement', 'view'),
          ('transport_pricing',  'view'),
          ('activity_pricing',   'view'),
          ('hotel',              'view'),
          ('transportation',     'view'),
          ('activity',           'view'),
          ('supplier',           'view'),
          ('driver',             'view'),
          ('vehicle',            'view'),
          ('settings',           'view')
      )
      INSERT INTO role_permissions (role_id, module, access_level, tenant_id, created_by, updated_by)
      SELECT
        shr.id,
        p.module,
        p.access_level::role_permissions_access_level_enum,
        shr.tenant_id,
        NULL,
        NULL
      FROM sales_head_roles shr
      CROSS JOIN perms p
      WHERE NOT EXISTS (
        SELECT 1 FROM role_permissions rp
        WHERE rp.role_id = shr.id
          AND rp.module = p.module
          AND rp.is_deleted = false
      )
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    // Hard-delete only the Sales Head role rows. role_permissions
    // rows cascade via the FK (onDelete: 'CASCADE' on the entity).
    // We don't unwind users assigned to this role — Admin must
    // reassign them first. If anyone is still on Sales Head when
    // this rolls back, the FK on users.role_id (RESTRICT/no-action)
    // will fail and force a manual cleanup, which is the safer
    // failure mode than silently re-pointing them.
    await queryRunner.query(`
      DELETE FROM roles
      WHERE name = 'Sales Head' AND is_system = true
    `);
  }
}
