import { test } from '@japa/runner'
import testUtils from '@adonisjs/core/services/test_utils'
import PlanStep from '#models/plan_step'
import { createTestUser, createTwoOrgs } from '../helpers/auth.js'
import { body, type ApiOk } from '../helpers/response.js'

type PlanShape = {
  id: string
  slug: string | null
  name: string
  description: string
  isDefault: boolean
  steps: Array<{ id: string; order: number; tone: string }>
  usageCount?: number
}

test.group('Plans — GET /plans', (group) => {
  group.each.setup(() => testUtils.db().withGlobalTransaction())

  test('retourne les 4 plans pré-fournis avec steps préchargés', async ({
    client,
    assert,
  }) => {
    const { bearer } = await createTestUser()
    const r = await client.get('/api/v1/plans').headers(bearer)
    r.assertStatus(200)

    const plans = body<ApiOk<PlanShape[]>>(r).data
    assert.lengthOf(plans, 4)
    for (const p of plans) {
      assert.isTrue(p.isDefault)
      assert.isAbove(p.steps.length, 0)
      assert.equal(p.usageCount, 0)
    }
  })

  test('isolation cross-org : chaque org voit ses propres copies', async ({
    client,
    assert,
  }) => {
    const { a, b } = await createTwoOrgs()
    const fromA = await client.get('/api/v1/plans').headers(a.bearer)
    const fromB = await client.get('/api/v1/plans').headers(b.bearer)

    const idsA = body<ApiOk<PlanShape[]>>(fromA).data.map((p) => p.id).sort()
    const idsB = body<ApiOk<PlanShape[]>>(fromB).data.map((p) => p.id).sort()
    for (const id of idsA) assert.notInclude(idsB, id)
  })
})

test.group('Plans — GET /plans/:slug', (group) => {
  group.each.setup(() => testUtils.db().withGlobalTransaction())

  test('lookup par slug avec steps ordonnés', async ({ client, assert }) => {
    const { bearer } = await createTestUser()
    const r = await client.get('/api/v1/plans/standard-30j').headers(bearer)
    r.assertStatus(200)

    const plan = body<ApiOk<PlanShape>>(r).data
    assert.equal(plan.slug, 'standard-30j')
    const orders = plan.steps.map((s) => s.order)
    assert.deepEqual(orders, [...orders].sort((a, b) => a - b))
  })

  test('404 si slug inconnu', async ({ client }) => {
    const { bearer } = await createTestUser()
    const r = await client.get('/api/v1/plans/inexistant').headers(bearer)
    r.assertStatus(404)
  })
})

test.group('Plans — PATCH /plans/:slug', (group) => {
  group.each.setup(() => testUtils.db().withGlobalTransaction())

  test('édite name + remplace les steps en bloc', async ({ client, assert }) => {
    const { bearer } = await createTestUser()

    const before = await client.get('/api/v1/plans/standard-30j').headers(bearer)
    const planId = body<ApiOk<PlanShape>>(before).data.id

    const r = await client
      .patch('/api/v1/plans/standard-30j')
      .headers(bearer)
      .json({
        name: 'Standard édité',
        steps: [
          {
            order: 0,
            offsetDays: 5,
            tone: 'amical',
            subject: 'Hop',
            body: 'Hop hop',
            requiresManualValidation: false,
          },
        ],
      })

    r.assertStatus(200)
    const data = body<ApiOk<PlanShape>>(r).data
    assert.equal(data.name, 'Standard édité')
    assert.lengthOf(data.steps, 1)

    const steps = await PlanStep.query().where('plan_id', planId)
    assert.lengthOf(steps, 1)
  })

  test('rejette tone invalide (422)', async ({ client }) => {
    const { bearer } = await createTestUser()
    const r = await client
      .patch('/api/v1/plans/standard-30j')
      .headers(bearer)
      .json({
        steps: [
          {
            order: 0,
            offsetDays: 1,
            tone: 'pas-un-ton',
            subject: 'X',
            body: 'X',
            requiresManualValidation: false,
          },
        ],
      })
    r.assertStatus(422)
  })

  test("cross-org : chaque org édite SA copie, pas celle de l'autre", async ({
    client,
    assert,
  }) => {
    const { a, b } = await createTwoOrgs()

    const r = await client
      .patch('/api/v1/plans/standard-30j')
      .headers(b.bearer)
      .json({ name: 'Renommé par B' })
    r.assertStatus(200)

    const fromA = await client.get('/api/v1/plans/standard-30j').headers(a.bearer)
    assert.equal(body<ApiOk<PlanShape>>(fromA).data.name, 'Standard B2B')
  })
})
