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

/**
 * Seeds three new system roles into every existing tenant
 * (client decision 2026-05-13):
 *
 *   - Transport Manager — VIEW everything on the Movement Dashboard,
 *     EDIT only transport-side assignments (driver/vehicle/supplier
 *     on transport rows). Explicit NONE on ACTIVITY_ASSIGNMENT so a
 *     future module added with VIEW default can't accidentally
 *     escalate them.
 *   - Activity Manager — mirror: VIEW everything, EDIT activity side
 *     only. NONE on TRANSPORT_ASSIGNMENT.
 *   - Accountant — VIEW everything; FE `useCanSeeTaxPercent` already
 *     includes this role name in its allow-list, so seeding the role
 *     here lets Admin actually assign it to users. EDIT on Payment
 *     Settlement comes when §12 ships.
 *
 * Companion code in tenant.service.ts SEED_ROLES — kept in lockstep.
 *
 * Module names referenced (already on the ModuleName enum):
 *   query, booking, booking_approval, driver_assignment,
 *   transport_assignment (NEW), activity_assignment (NEW),
 *   movement_chart, payment_settlement, transport_pricing,
 *   activity_pricing, hotel, transportation, activity, supplier,
 *   driver, vehicle, settings.
 *
 * Idempotent: re-running is a no-op. Existing data on dev is mock
 * (client confirmed) so this migration doesn't try to preserve any
 * previous Transport/Activity Manager permissions.
 */
export class TransportActivityAccountantRoles1778400000000 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    // Step 1 — insert the three roles per tenant if not already there.
    await queryRunner.query(`
      INSERT INTO roles (name, description, is_system, tenant_id, created_by, updated_by)
      SELECT v.name, v.description, true, t.id, NULL, NULL
      FROM tenants t
      CROSS JOIN (VALUES
        ('Transport Manager', 'Edit transport assignments on the Movement Dashboard (driver / vehicle / supplier on transport rows)'),
        ('Activity Manager',  'Edit activity assignments on the Movement Dashboard (supplier / pricing / status on activity rows)'),
        ('Accountant',        'View pricing, taxes, and settlements; ready for Phase-1.5 finance workflows')
      ) AS v(name, description)
      WHERE NOT EXISTS (
        SELECT 1 FROM roles r
        WHERE r.tenant_id = t.id AND r.name = v.name AND r.is_deleted = false
      )
    `);

    // Step 2 — populate role_permissions for the three new roles.
    // Each role gets a row per ModuleName value with the appropriate
    // access_level. Encoded inline so the migration is self-contained.
    // Re-runnable via WHERE NOT EXISTS on each row.
    //
    // Defaults below mirror SEED_ROLES in tenant.service.ts. If you
    // edit the seed there, run this migration's down + up to resync.
    await queryRunner.query(`
      WITH new_roles AS (
        SELECT id, tenant_id, name FROM roles
        WHERE name IN ('Transport Manager', 'Activity Manager', 'Accountant')
          AND is_deleted = false
      ),
      perms (role_name, module, access_level) AS (
        VALUES
          -- Transport Manager: VIEW default, EDIT on transport_assignment,
          -- NONE on activity_assignment (explicit).
          ('Transport Manager', 'query',                'view'),
          ('Transport Manager', 'booking',              'view'),
          ('Transport Manager', 'booking_approval',     'view'),
          ('Transport Manager', 'driver_assignment',    'view'),
          ('Transport Manager', 'transport_assignment', 'edit'),
          ('Transport Manager', 'activity_assignment',  'none'),
          ('Transport Manager', 'movement_chart',       'view'),
          ('Transport Manager', 'payment_settlement',   'view'),
          ('Transport Manager', 'transport_pricing',    'view'),
          ('Transport Manager', 'activity_pricing',     'view'),
          ('Transport Manager', 'hotel',                'view'),
          ('Transport Manager', 'transportation',       'view'),
          ('Transport Manager', 'activity',             'view'),
          ('Transport Manager', 'supplier',             'view'),
          ('Transport Manager', 'driver',               'view'),
          ('Transport Manager', 'vehicle',              'view'),
          ('Transport Manager', 'settings',             'view'),
          -- Activity Manager: mirror — VIEW default, EDIT on
          -- activity_assignment, NONE on transport_assignment.
          ('Activity Manager',  'query',                'view'),
          ('Activity Manager',  'booking',              'view'),
          ('Activity Manager',  'booking_approval',     'view'),
          ('Activity Manager',  'driver_assignment',    'view'),
          ('Activity Manager',  'transport_assignment', 'none'),
          ('Activity Manager',  'activity_assignment',  'edit'),
          ('Activity Manager',  'movement_chart',       'view'),
          ('Activity Manager',  'payment_settlement',   'view'),
          ('Activity Manager',  'transport_pricing',    'view'),
          ('Activity Manager',  'activity_pricing',     'view'),
          ('Activity Manager',  'hotel',                'view'),
          ('Activity Manager',  'transportation',       'view'),
          ('Activity Manager',  'activity',             'view'),
          ('Activity Manager',  'supplier',             'view'),
          ('Activity Manager',  'driver',               'view'),
          ('Activity Manager',  'vehicle',              'view'),
          ('Activity Manager',  'settings',             'view'),
          -- Accountant: blanket VIEW. Edit on payment_settlement and
          -- specific finance modules is a Phase-1.5 follow-up.
          ('Accountant',        'query',                'view'),
          ('Accountant',        'booking',              'view'),
          ('Accountant',        'booking_approval',     'view'),
          ('Accountant',        'driver_assignment',    'view'),
          ('Accountant',        'transport_assignment', 'view'),
          ('Accountant',        'activity_assignment',  'view'),
          ('Accountant',        'movement_chart',       'view'),
          ('Accountant',        'payment_settlement',   'view'),
          ('Accountant',        'transport_pricing',    'view'),
          ('Accountant',        'activity_pricing',     'view'),
          ('Accountant',        'hotel',                'view'),
          ('Accountant',        'transportation',       'view'),
          ('Accountant',        'activity',             'view'),
          ('Accountant',        'supplier',             'view'),
          ('Accountant',        'driver',               'view'),
          ('Accountant',        'vehicle',              'view'),
          ('Accountant',        'settings',             'view')
      )
      INSERT INTO role_permissions (role_id, module, access_level, tenant_id, created_by, updated_by)
      SELECT
        nr.id,
        p.module,
        p.access_level::role_permissions_access_level_enum,
        nr.tenant_id,
        NULL,
        NULL
      FROM new_roles nr
      JOIN perms p ON p.role_name = nr.name
      WHERE NOT EXISTS (
        SELECT 1 FROM role_permissions rp
        WHERE rp.role_id = nr.id
          AND rp.module = p.module
          AND rp.is_deleted = false
      )
    `);

    // Step 3 — also backfill TRANSPORT_ASSIGNMENT + ACTIVITY_ASSIGNMENT
    // permission rows for EXISTING seed roles (Admin / Ops Manager /
    // Trip Coordinator / Sales Head / Sales Team), so their behaviour
    // on the renamed-permission endpoints is preserved.
    //
    // Strategy: copy the role's existing `driver_assignment` access
    // level → BOTH new modules. Admin's DELETE flows through;
    // Operations Manager's EDIT flows through; Sales Team's VIEW flows
    // through. Anyone who could edit transport+activity before still
    // can after.
    await queryRunner.query(`
      INSERT INTO role_permissions (role_id, module, access_level, tenant_id, created_by, updated_by)
      SELECT
        rp.role_id,
        v.new_module,
        rp.access_level,
        rp.tenant_id,
        NULL,
        NULL
      FROM role_permissions rp
      CROSS JOIN (VALUES ('transport_assignment'), ('activity_assignment')) AS v(new_module)
      WHERE rp.module = 'driver_assignment'
        AND rp.is_deleted = false
        AND NOT EXISTS (
          SELECT 1 FROM role_permissions rp2
          WHERE rp2.role_id = rp.role_id
            AND rp2.module = v.new_module
            AND rp2.is_deleted = false
        )
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    // Hard-delete the three roles (role_permissions cascade via the
    // FK onDelete: 'CASCADE'). Then drop the backfilled rows on
    // pre-existing roles too — they were derived from driver_assignment
    // and we don't have a reliable way to distinguish them otherwise.
    await queryRunner.query(`
      DELETE FROM roles
      WHERE name IN ('Transport Manager', 'Activity Manager', 'Accountant')
        AND is_system = true
    `);
    await queryRunner.query(`
      DELETE FROM role_permissions
      WHERE module IN ('transport_assignment', 'activity_assignment')
    `);
  }
}
