import { query, withTransaction } from '../db/client.js'

type FulfillmentProfileRow = {
  id: number
  profile_key: string
  name: string
  executor_key: string
  requires_claim: boolean
  auto_dispatch: boolean
  inventory_strategy: string
  config_json: string | Record<string, unknown>
  created_at: string
  updated_at: string
}

type FulfillmentProfileRequirementRow = {
  id: number
  profile_id: number
  role_key: string
  roleKey?: string
  credential_type: string
  credentialType?: string
  quantity_per_unit: number
  is_required: boolean
  config_json: string | Record<string, unknown>
  created_at: string
  updated_at: string
}

type SkuFulfillmentBindingRow = {
  id: number
  sku_code: string
  provider: string
  platform: string
  shop_id: string
  profile_id: number
  enabled: boolean
  priority: number
  config_json: string | Record<string, unknown>
  created_at: string
  updated_at: string
  profile_key?: string
  name?: string
  profile_name?: string
  executor_key?: string
  requires_claim?: boolean
  auto_dispatch?: boolean
  inventory_strategy?: string
  profile_config_json?: string | Record<string, unknown>
}

type FulfillmentProfileUpsertInput = {
  profileKey: string
  name: string
  executorKey: string
  requiresClaim?: boolean
  autoDispatch?: boolean
  inventoryStrategy?: string
  configJson?: string | Record<string, unknown>
  createdAt: string
  updatedAt: string
}

type FulfillmentProfileRequirementInput = {
  roleKey: string
  credentialType: string
  quantityPerUnit?: number | string
  isRequired?: boolean
  configJson?: string | Record<string, unknown>
}

type SkuFulfillmentBindingUpsertInput = {
  skuCode: string
  provider?: string
  platform?: string
  shopId?: string
  profileId: number | string
  enabled?: boolean
  priority?: number | string
  configJson?: string | Record<string, unknown>
  createdAt: string
  updatedAt: string
}

type FulfillmentBindingResolveInput = {
  skuCode: string
  provider?: string
  platform?: string
  shopId?: string
}

export async function getFulfillmentProfileByKey(profileKey: string): Promise<FulfillmentProfileRow | null> {
  const result = await query<FulfillmentProfileRow>(
    'SELECT * FROM fulfillment_profiles WHERE profile_key = $1 LIMIT 1',
    [String(profileKey || '').trim()],
  )
  return result.rows[0] || null
}

export async function upsertFulfillmentProfile(
  input: FulfillmentProfileUpsertInput,
): Promise<FulfillmentProfileRow | null> {
  const result = await query<FulfillmentProfileRow>(
    `
      INSERT INTO fulfillment_profiles (
        profile_key,
        name,
        executor_key,
        requires_claim,
        auto_dispatch,
        inventory_strategy,
        config_json,
        created_at,
        updated_at
      ) VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8, $9)
      ON CONFLICT (profile_key) DO UPDATE
      SET
        name = EXCLUDED.name,
        executor_key = EXCLUDED.executor_key,
        requires_claim = EXCLUDED.requires_claim,
        auto_dispatch = EXCLUDED.auto_dispatch,
        inventory_strategy = EXCLUDED.inventory_strategy,
        config_json = EXCLUDED.config_json,
        updated_at = EXCLUDED.updated_at
      RETURNING *
    `,
    [
      input.profileKey,
      input.name,
      input.executorKey,
      Boolean(input.requiresClaim),
      Boolean(input.autoDispatch),
      input.inventoryStrategy || 'static_pool',
      input.configJson || '{}',
      input.createdAt,
      input.updatedAt,
    ],
  )

  return result.rows[0] || null
}

export async function replaceFulfillmentProfileRequirements(
  profileId: number | string,
  requirements: FulfillmentProfileRequirementInput[] = [],
  timestamp: string,
): Promise<void> {
  await withTransaction(async (client) => {
    await client.query(
      'DELETE FROM fulfillment_profile_requirements WHERE profile_id = $1',
      [Number(profileId)],
    )

    for (const requirement of requirements) {
      await client.query(
        `
          INSERT INTO fulfillment_profile_requirements (
            profile_id,
            role_key,
            credential_type,
            quantity_per_unit,
            is_required,
            config_json,
            created_at,
            updated_at
          ) VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7, $8)
        `,
        [
          Number(profileId),
          requirement.roleKey,
          requirement.credentialType,
          Number(requirement.quantityPerUnit || 1),
          requirement.isRequired !== false,
          requirement.configJson || '{}',
          timestamp,
          timestamp,
        ],
      )
    }
  })
}

export async function listFulfillmentProfileRequirements(
  profileId: number | string,
): Promise<FulfillmentProfileRequirementRow[]> {
  const result = await query<FulfillmentProfileRequirementRow>(
    `
      SELECT *
      FROM fulfillment_profile_requirements
      WHERE profile_id = $1
      ORDER BY id ASC
    `,
    [Number(profileId)],
  )

  return result.rows
}

export async function upsertSkuFulfillmentBinding(
  input: SkuFulfillmentBindingUpsertInput,
): Promise<SkuFulfillmentBindingRow | null> {
  const existing = await query<SkuFulfillmentBindingRow>(
    `
      SELECT *
      FROM sku_fulfillment_bindings
      WHERE sku_code = $1 AND provider = $2 AND platform = $3 AND shop_id = $4
      LIMIT 1
    `,
    [input.skuCode, input.provider || '', input.platform || '', input.shopId || ''],
  )

  if (!existing.rows[0]) {
    const inserted = await query<SkuFulfillmentBindingRow>(
      `
        INSERT INTO sku_fulfillment_bindings (
          sku_code,
          provider,
          platform,
          shop_id,
          profile_id,
          enabled,
          priority,
          config_json,
          created_at,
          updated_at
        ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9, $10)
        RETURNING *
      `,
      [
        input.skuCode,
        input.provider || '',
        input.platform || '',
        input.shopId || '',
        Number(input.profileId),
        input.enabled !== false,
        Number(input.priority || 100),
        input.configJson || '{}',
        input.createdAt,
        input.updatedAt,
      ],
    )

    return inserted.rows[0] || null
  }

  const updated = await query<SkuFulfillmentBindingRow>(
    `
      UPDATE sku_fulfillment_bindings
      SET
        profile_id = $1,
        enabled = $2,
        priority = $3,
        config_json = $4::jsonb,
        updated_at = $5
      WHERE id = $6
      RETURNING *
    `,
    [
      Number(input.profileId),
      input.enabled !== false,
      Number(input.priority || 100),
      input.configJson || '{}',
      input.updatedAt,
      Number(existing.rows[0].id),
    ],
  )

  return updated.rows[0] || null
}

export async function resolveFulfillmentBinding({
  skuCode,
  provider = '',
  platform = '',
  shopId = '',
}: FulfillmentBindingResolveInput): Promise<SkuFulfillmentBindingRow | null> {
  const result = await query<SkuFulfillmentBindingRow>(
    `
      SELECT
        sfb.*,
        fp.profile_key,
        fp.name AS profile_name,
        fp.executor_key,
        fp.requires_claim,
        fp.auto_dispatch,
        fp.inventory_strategy,
        fp.config_json AS profile_config_json
      FROM sku_fulfillment_bindings sfb
      JOIN fulfillment_profiles fp ON fp.id = sfb.profile_id
      WHERE sfb.enabled = TRUE
        AND sfb.sku_code = $1
        AND (sfb.provider = '' OR sfb.provider = $2)
        AND (sfb.platform = '' OR sfb.platform = $3)
        AND (sfb.shop_id = '' OR sfb.shop_id = $4)
      ORDER BY
        CASE WHEN sfb.shop_id = '' THEN 1 ELSE 0 END,
        CASE WHEN sfb.platform = '' THEN 1 ELSE 0 END,
        CASE WHEN sfb.provider = '' THEN 1 ELSE 0 END,
        sfb.priority ASC,
        sfb.id ASC
      LIMIT 1
    `,
    [skuCode, provider, platform, shopId],
  )

  return result.rows[0] || null
}
