import { HttpError, type RequestContext } from '../../core/http.js';
import { intParam, stringParam, tenantIdFrom } from '../../core/request.js';
import { query, queryOne } from '../../core/db.js';

function optionalUuidParam(ctx: RequestContext, name: string) {
  const value = stringParam(ctx, name);
  return value || null;
}

export async function contentEntriesRoute(ctx: RequestContext) {
  const tenantId = await tenantIdFrom(ctx);
  const regionId = optionalUuidParam(ctx, 'regionId');
  const entryType = stringParam(ctx, 'entryType');
  const includeHidden = stringParam(ctx, 'includeHidden') === 'true';

  const params: unknown[] = [tenantId];
  const filters = ['tenant_id = $1', 'is_active = true'];
  if (!includeHidden) filters.push(`visibility <> 'hidden'`);
  if (regionId) {
    params.push(regionId);
    filters.push(`(region_id = $${params.length} or region_id is null)`);
  }
  if (entryType) {
    params.push(entryType);
    filters.push(`entry_type = $${params.length}`);
  }

  const items = await query(
    `
    select id, region_id as "regionId", legacy_id as "legacyId",
           entry_key as "entryKey", name, entry_type as "entryType",
           icon, route, description, visibility, access_rules as "accessRules",
           layout_config as "layoutConfig", sort_order as "order",
           is_active as "isActive", created_at as "createdAt",
           updated_at as "updatedAt"
    from public.content_entries
    where ${filters.join(' and ')}
    order by sort_order asc, created_at asc
    `,
    params,
  );

  return { items };
}

export async function contentNodesRoute(ctx: RequestContext) {
  const tenantId = await tenantIdFrom(ctx);
  const entryId = stringParam(ctx, 'entryId');
  if (!entryId) {
    throw new HttpError(400, 'entryId is required', 'REQUIRED_FIELD');
  }

  const parentIdParam = ctx.url.searchParams.get('parentId');
  const parentId = parentIdParam === 'root' ? null : parentIdParam;
  const mode = stringParam(ctx, 'mode') || 'children';
  const includeInactive = stringParam(ctx, 'includeInactive') === 'true';
  const markerType = stringParam(ctx, 'markerType');

  const params: unknown[] = [tenantId, entryId];
  const filters = ['tenant_id = $1', 'entry_id = $2'];
  if (!includeInactive) filters.push('is_active = true');
  if (parentIdParam !== null) {
    if (parentId) {
      params.push(parentId);
      filters.push(`parent_id = $${params.length}`);
    } else {
      filters.push('parent_id is null');
    }
  }
  if (markerType) {
    params.push(markerType);
    filters.push(`marker_type = $${params.length}`);
  }

  const orderClause = mode === 'flat'
    ? 'coalesce(path::text, name) asc, sort_order asc'
    : 'sort_order asc, created_at asc';

  const items = await query(
    `
    select id, entry_id as "entryId", region_id as "regionId",
           parent_id as "parentId", legacy_id as "legacyId",
           node_key as "nodeKey", name, node_type as "nodeType",
           marker_type as "markerType", marker_config as "markerConfig",
           path::text as path, depth, sort_order as "order",
           is_active as "isActive", is_selectable as "isSelectable",
           is_leaf as "isLeaf", access_rules as "accessRules", metadata,
           created_at as "createdAt", updated_at as "updatedAt"
    from public.content_nodes
    where ${filters.join(' and ')}
    order by ${orderClause}
    `,
    params,
  );

  return { items };
}

export async function questionCollectionsRoute(ctx: RequestContext) {
  const tenantId = await tenantIdFrom(ctx);
  const regionId = optionalUuidParam(ctx, 'regionId');
  const entryId = optionalUuidParam(ctx, 'entryId');
  const nodeId = optionalUuidParam(ctx, 'nodeId');
  const collectionType = stringParam(ctx, 'collectionType');
  const limit = intParam(ctx, 'limit', 100, 500);

  const params: unknown[] = [tenantId];
  const filters = ['tenant_id = $1', `status = 'active'`];
  if (regionId) {
    params.push(regionId);
    filters.push(`(region_id = $${params.length} or region_id is null)`);
  }
  if (entryId) {
    params.push(entryId);
    filters.push(`entry_id = $${params.length}`);
  }
  if (nodeId) {
    params.push(nodeId);
    filters.push(`node_id = $${params.length}`);
  }
  if (collectionType) {
    params.push(collectionType);
    filters.push(`collection_type = $${params.length}`);
  }
  params.push(limit);

  const items = await query(
    `
    select id, region_id as "regionId", entry_id as "entryId",
           node_id as "nodeId", subject_id as "subjectId",
           category_id as "categoryId", question_bank_id as "questionBankId",
           legacy_id as "legacyId", name, collection_type as "collectionType",
           source_type as "sourceType", filters, question_count as "questionCount",
           total_score as "totalScore", duration_minutes as "durationMinutes",
           status, sort_order as "order", access_rules as "accessRules", metadata,
           created_at as "createdAt", updated_at as "updatedAt"
    from public.question_collections
    where ${filters.join(' and ')}
    order by sort_order asc, created_at asc
    limit $${params.length}
    `,
    params,
  );

  return { items };
}

export async function practiceBlueprintsRoute(ctx: RequestContext) {
  const tenantId = await tenantIdFrom(ctx);
  const entryId = optionalUuidParam(ctx, 'entryId');
  const nodeId = optionalUuidParam(ctx, 'nodeId');
  const collectionId = optionalUuidParam(ctx, 'collectionId');
  const mode = stringParam(ctx, 'mode');
  const limit = intParam(ctx, 'limit', 100, 500);

  const params: unknown[] = [tenantId];
  const filters = ['tenant_id = $1', `status = 'active'`];
  if (entryId) {
    params.push(entryId);
    filters.push(`entry_id = $${params.length}`);
  }
  if (nodeId) {
    params.push(nodeId);
    filters.push(`node_id = $${params.length}`);
  }
  if (collectionId) {
    params.push(collectionId);
    filters.push(`collection_id = $${params.length}`);
  }
  if (mode) {
    params.push(mode);
    filters.push(`mode = $${params.length}`);
  }
  params.push(limit);

  const items = await query(
    `
    select id, region_id as "regionId", entry_id as "entryId",
           node_id as "nodeId", collection_id as "collectionId",
           legacy_id as "legacyId", name, mode,
           assembly_type as "assemblyType", question_limit as "questionLimit",
           duration_minutes as "durationMinutes", total_score as "totalScore",
           pass_score as "passScore", sections, rules, access_rules as "accessRules", status,
           sort_order as "order", created_at as "createdAt",
           updated_at as "updatedAt"
    from public.practice_blueprints
    where ${filters.join(' and ')}
    order by sort_order asc, created_at asc
    limit $${params.length}
    `,
    params,
  );

  return { items };
}

export async function collectionQuestionsRoute(ctx: RequestContext) {
  const tenantId = await tenantIdFrom(ctx);
  const collectionId = stringParam(ctx, 'collectionId');
  if (!collectionId) {
    throw new HttpError(400, 'collectionId is required', 'REQUIRED_FIELD');
  }
  const limit = intParam(ctx, 'limit', 200, 1000);

  const collection = await queryOne<{ id: string }>(
    `
    select id
    from public.question_collections
    where tenant_id = $1 and id = $2 and status = 'active'
    limit 1
    `,
    [tenantId, collectionId],
  );
  if (!collection) {
    throw new HttpError(404, 'Question collection not found', 'QUESTION_COLLECTION_NOT_FOUND');
  }

  const items = await query(
    `
    select q.id, q.legacy_id as "legacyId", q.entry_id as "entryId",
           q.content_node_id as "contentNodeId",
           q.primary_collection_id as "primaryCollectionId",
           q.subject_id as "subjectId", q.category_id as "categoryId",
           q.node_id as "nodeId", q.type, q.type_label as "typeLabel",
           q.difficulty, q.tags, q.exam_markers as "examMarkers",
           q.media_url as "mediaUrl", q.has_video_explanation as "hasVideoExplanation",
           ci.section_key as "sectionKey", ci.score, ci.sort_order as "order",
           v.id as "versionId", v.content, v.options,
           v.correct_option_index as "correctOptionIndex",
           v.correct_option_indices as "correctOptionIndices",
           v.answer_text as "answerText", v.explanation, v.sub_questions as "subQuestions",
           v.code_lang as "codeLang", v.code_template as "codeTemplate",
           q.created_at as "createdAt", q.updated_at as "updatedAt"
    from public.question_collection_items ci
    join public.questions q on q.id = ci.question_id and q.tenant_id = ci.tenant_id
    left join public.question_versions v on v.id = q.current_version_id
    where ci.tenant_id = $1
      and ci.collection_id = $2
      and q.status = 'published'
    order by ci.section_key asc nulls first, ci.sort_order asc, q.created_at asc
    limit $3
    `,
    [tenantId, collectionId, limit],
  );

  return { items };
}
