import request from 'supertest';
import { DeviceStatus, Role } from '../../../src/generated/prisma/enums.js';
import {
  closeE2EContext,
  createE2EContext,
  type E2EContext,
} from '../helpers/e2e-context.helper.js';
import { assertRoleMatrix } from '../helpers/e2e-matrix.helper.js';
import {
  expectErrorEnvelope,
  expectSuccessEnvelope,
  uniqueSeedValue,
} from '../helpers/e2e-http.helper.js';

describe('BDevicesController (e2e)', () => {
  let ctx: E2EContext;

  beforeAll(async () => {
    ctx = await createE2EContext();
  });

  afterAll(async () => {
    await closeE2EContext(ctx);
  });

  async function createDevice(token: string, patientId: number) {
    const response = await request(ctx.app.getHttpServer())
      .post('/b/devices')
      .set('Authorization', `Bearer ${token}`)
      .send({
        status: DeviceStatus.ACTIVE,
        patientId,
      });

    expectSuccessEnvelope(response, 201);
    return response.body.data as {
      id: number;
      currentPressure: string;
      status: DeviceStatus;
      patient: { id: number };
    };
  }

  describe('GET /b/devices', () => {
    it('成功：SYSTEM_ADMIN 可分页查询设备列表', async () => {
      const response = await request(ctx.app.getHttpServer())
        .get('/b/devices')
        .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`);

      expectSuccessEnvelope(response, 200);
      expect(Array.isArray(response.body.data.list)).toBe(true);
      expect(response.body.data.total).toBeGreaterThan(0);
    });

    it('成功：HOSPITAL_ADMIN 仅能看到本院设备', async () => {
      const response = await request(ctx.app.getHttpServer())
        .get('/b/devices')
        .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`);

      expectSuccessEnvelope(response, 200);
      const hospitalIds = (
        response.body.data.list as Array<{
          patient?: { hospital?: { id: number } };
        }>
      )
        .map((item) => item.patient?.hospital?.id)
        .filter(Boolean);

      expect(hospitalIds.every((id) => id === ctx.fixtures.hospitalAId)).toBe(
        true,
      );
    });

    it('角色矩阵：仅 SYSTEM_ADMIN/HOSPITAL_ADMIN 可访问列表，其他角色 403，未登录 401', async () => {
      await assertRoleMatrix({
        name: 'GET /b/devices role matrix',
        tokens: ctx.tokens,
        expectedStatusByRole: {
          [Role.SYSTEM_ADMIN]: 200,
          [Role.HOSPITAL_ADMIN]: 200,
          [Role.DIRECTOR]: 403,
          [Role.LEADER]: 403,
          [Role.DOCTOR]: 403,
          [Role.ENGINEER]: 403,
        },
        sendAsRole: async (_role, token) =>
          request(ctx.app.getHttpServer())
            .get('/b/devices')
            .set('Authorization', `Bearer ${token}`),
        sendWithoutToken: async () =>
          request(ctx.app.getHttpServer()).get('/b/devices'),
      });
    });
  });

  describe('植入物型号字典', () => {
    it('成功：DOCTOR 可查询可见型号字典', async () => {
      const response = await request(ctx.app.getHttpServer())
        .get('/b/devices/catalogs')
        .set('Authorization', `Bearer ${ctx.tokens[Role.DOCTOR]}`);

      expectSuccessEnvelope(response, 200);
      expect(
        (response.body.data as Array<{ modelCode: string }>).some(
          (item) => item.modelCode === 'SEED-ADJUSTABLE-VALVE',
        ),
      ).toBe(true);
    });

    it('成功：SYSTEM_ADMIN 可新增、更新并删除全局植入物目录', async () => {
      const createResponse = await request(ctx.app.getHttpServer())
        .post('/b/devices/catalogs')
        .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`)
        .send({
          modelCode: uniqueSeedValue('catalog').toUpperCase(),
          manufacturer: 'Global Vendor',
          name: '全局可调压阀',
          isValve: true,
          pressureLevels: ['10.0', '20', '30.0'],
          notes: '测试全局目录',
        });

      expectSuccessEnvelope(createResponse, 201);
      expect(createResponse.body.data.isValve).toBe(true);
      expect(createResponse.body.data.pressureLevels).toEqual([
        '10',
        '20',
        '30',
      ]);

      const updateResponse = await request(ctx.app.getHttpServer())
        .patch(`/b/devices/catalogs/${createResponse.body.data.id}`)
        .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`)
        .send({
          name: '全局可调压阀-更新版',
          pressureLevels: ['0.5', '1.0', '1.50'],
        });

      expectSuccessEnvelope(updateResponse, 200);
      expect(updateResponse.body.data.name).toBe('全局可调压阀-更新版');
      expect(updateResponse.body.data.isValve).toBe(true);
      expect(updateResponse.body.data.pressureLevels).toEqual([
        '0.5',
        '1',
        '1.5',
      ]);

      const deleteResponse = await request(ctx.app.getHttpServer())
        .delete(`/b/devices/catalogs/${createResponse.body.data.id}`)
        .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`);

      expectSuccessEnvelope(deleteResponse, 200);
      expect(deleteResponse.body.data.id).toBe(createResponse.body.data.id);
    });

    it('成功：SYSTEM_ADMIN 可新增非阀门目录，且不会保存压力挡位', async () => {
      const response = await request(ctx.app.getHttpServer())
        .post('/b/devices/catalogs')
        .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`)
        .send({
          modelCode: uniqueSeedValue('tube').toUpperCase(),
          manufacturer: 'Global Vendor',
          name: '腹腔管',
          isValve: false,
          pressureLevels: ['1', '2'],
        });

      expectSuccessEnvelope(response, 201);
      expect(response.body.data.isValve).toBe(false);
      expect(response.body.data.isPressureAdjustable).toBe(false);
      expect(response.body.data.pressureLevels).toEqual([]);
    });

    it('角色矩阵：仅 SYSTEM_ADMIN 可维护全局植入物目录', async () => {
      await assertRoleMatrix({
        name: 'POST /b/devices/catalogs role matrix',
        tokens: ctx.tokens,
        expectedStatusByRole: {
          [Role.SYSTEM_ADMIN]: 201,
          [Role.HOSPITAL_ADMIN]: 403,
          [Role.DIRECTOR]: 403,
          [Role.LEADER]: 403,
          [Role.DOCTOR]: 403,
          [Role.ENGINEER]: 403,
        },
        sendAsRole: async (_role, token) =>
          request(ctx.app.getHttpServer())
            .post('/b/devices/catalogs')
            .set('Authorization', `Bearer ${token}`)
            .send({
              modelCode: uniqueSeedValue('catalog-role').toUpperCase(),
              manufacturer: 'Role Matrix Vendor',
              name: '角色矩阵目录',
              isValve: true,
              pressureLevels: ['10', '20'],
            }),
        sendWithoutToken: async () =>
          request(ctx.app.getHttpServer())
            .post('/b/devices/catalogs')
            .send({
              modelCode: uniqueSeedValue('catalog-anon').toUpperCase(),
              manufacturer: 'Anon Vendor',
              name: '匿名目录',
            }),
      });
    });
  });

  describe('设备 CRUD 流程', () => {
    it('成功：HOSPITAL_ADMIN 可创建设备', async () => {
      const created = await createDevice(
        ctx.tokens[Role.HOSPITAL_ADMIN],
        ctx.fixtures.patients.patientA1Id,
      );

      expect(created.status).toBe(DeviceStatus.ACTIVE);
      expect(created.currentPressure).toBe('0');
      expect(created.patient.id).toBe(ctx.fixtures.patients.patientA1Id);
      expect(created).not.toHaveProperty('snCode');
    });

    it('失败：HOSPITAL_ADMIN 绑定跨院患者返回 403', async () => {
      const response = await request(ctx.app.getHttpServer())
        .post('/b/devices')
        .set('Authorization', `Bearer ${ctx.tokens[Role.HOSPITAL_ADMIN]}`)
        .send({
          status: DeviceStatus.ACTIVE,
          patientId: ctx.fixtures.patients.patientB1Id,
        });

      expectErrorEnvelope(response, 403, '仅可绑定当前权限范围内患者');
    });

    it('成功：SYSTEM_ADMIN 可更新设备状态与归属患者', async () => {
      const created = await createDevice(
        ctx.tokens[Role.SYSTEM_ADMIN],
        ctx.fixtures.patients.patientA1Id,
      );

      const response = await request(ctx.app.getHttpServer())
        .patch(`/b/devices/${created.id}`)
        .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`)
        .send({
          status: DeviceStatus.INACTIVE,
          patientId: ctx.fixtures.patients.patientA2Id,
        });

      expectSuccessEnvelope(response, 200);
      expect(response.body.data.status).toBe(DeviceStatus.INACTIVE);
      expect(response.body.data.patient.id).toBe(
        ctx.fixtures.patients.patientA2Id,
      );
      expect(response.body.data.currentPressure).toBe('0');
    });

    it('失败：设备实例接口不允许手工更新 currentPressure', async () => {
      const created = await createDevice(
        ctx.tokens[Role.SYSTEM_ADMIN],
        ctx.fixtures.patients.patientA1Id,
      );

      const response = await request(ctx.app.getHttpServer())
        .patch(`/b/devices/${created.id}`)
        .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`)
        .send({
          currentPressure: '1.5',
        });

      expectErrorEnvelope(response, 400, 'currentPressure should not exist');
    });

    it('成功：SYSTEM_ADMIN 可删除未被任务引用的设备', async () => {
      const created = await createDevice(
        ctx.tokens[Role.SYSTEM_ADMIN],
        ctx.fixtures.patients.patientA1Id,
      );

      const response = await request(ctx.app.getHttpServer())
        .delete(`/b/devices/${created.id}`)
        .set('Authorization', `Bearer ${ctx.tokens[Role.SYSTEM_ADMIN]}`);

      expectSuccessEnvelope(response, 200);
      expect(response.body.data.id).toBe(created.id);
    });
  });
});
