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

const CONTENT_ROLES = new Set(['tenant_owner', 'tenant_admin', 'tenant_operator', 'teacher']);

export interface TenantContentAuth {
  tenantId: string;
  userId: string;
  role: string;
  permissions: Record<string, unknown>;
  templatePermissions: Record<string, unknown>;
}

function hasContentPermission(permissions: Record<string, unknown>) {
  return permissions['*'] === true || permissions['content:*'] === true;
}

function hasPermission(permissions: Record<string, unknown>, permissionKey: string) {
  return permissions['*'] === true || permissions['content:*'] === true || permissions[permissionKey] === true;
}

export async function requireTenantContentEditor(ctx: RequestContext): Promise<TenantContentAuth> {
  const tenantId = await tenantIdFrom(ctx);
  const userId = await userIdFrom(ctx);

  const membership = await queryOne<{ role: string; permissions: Record<string, unknown>; templatePermissions: Record<string, unknown> }>(
    `
    select tm.role, tm.permissions,
           coalesce(rt.permissions, '{}'::jsonb) as "templatePermissions"
    from public.tenant_memberships tm
    left join public.tenant_role_templates rt
      on rt.id = tm.role_template_id
     and rt.tenant_id = tm.tenant_id
     and rt.status = 'active'
    where tm.tenant_id = $1
      and tm.user_id = $2
      and tm.status = 'active'
      and (
        tm.role = any($3::text[])
        or coalesce(rt.permissions, '{}'::jsonb) ? 'content:*'
        or coalesce(rt.permissions, '{}'::jsonb) ? '*'
        or tm.permissions ? 'content:*'
        or tm.permissions ? '*'
      )
    order by case tm.role
      when 'tenant_owner' then 1
      when 'tenant_admin' then 2
      when 'tenant_operator' then 3
      when 'teacher' then 4
      else 9
    end
    limit 1
    `,
    [tenantId, userId, Array.from(CONTENT_ROLES)],
  );

  if (!membership) {
    throw new HttpError(403, 'Tenant content editor access is required', 'TENANT_CONTENT_EDITOR_REQUIRED');
  }
  if (!CONTENT_ROLES.has(membership.role) && !hasContentPermission(membership.permissions || {}) && !hasContentPermission(membership.templatePermissions || {})) {
    throw new HttpError(403, 'Tenant content editor access is required', 'TENANT_CONTENT_EDITOR_REQUIRED');
  }

  return { tenantId, userId, role: membership.role, permissions: membership.permissions || {}, templatePermissions: membership.templatePermissions || {} };
}

export async function requireTenantContentPermission(
  ctx: RequestContext,
  permissionKey: string,
  defaultRoles: string[] = ['tenant_owner', 'tenant_admin', 'tenant_operator'],
): Promise<TenantContentAuth> {
  const tenantId = await tenantIdFrom(ctx);
  const userId = await userIdFrom(ctx);

  const membership = await queryOne<{ role: string; permissions: Record<string, unknown>; templatePermissions: Record<string, unknown> }>(
    `
    select tm.role, tm.permissions,
           coalesce(rt.permissions, '{}'::jsonb) as "templatePermissions"
    from public.tenant_memberships tm
    left join public.tenant_role_templates rt
      on rt.id = tm.role_template_id
     and rt.tenant_id = tm.tenant_id
     and rt.status = 'active'
    where tm.tenant_id = $1
      and tm.user_id = $2
      and tm.status = 'active'
      and (
        tm.role = any($3::text[])
        or coalesce(rt.permissions, '{}'::jsonb) ? $4
        or coalesce(rt.permissions, '{}'::jsonb) ? 'content:*'
        or coalesce(rt.permissions, '{}'::jsonb) ? '*'
        or tm.permissions ? $4
        or tm.permissions ? 'content:*'
        or tm.permissions ? '*'
      )
    order by case tm.role
      when 'tenant_owner' then 1
      when 'tenant_admin' then 2
      when 'tenant_operator' then 3
      when 'teacher' then 4
      else 9
    end
    limit 1
    `,
    [tenantId, userId, defaultRoles, permissionKey],
  );

  if (!membership) {
    throw new HttpError(403, 'Tenant content permission is required', 'TENANT_CONTENT_PERMISSION_REQUIRED');
  }
  const permissions = membership.permissions || {};
  const templatePermissions = membership.templatePermissions || {};
  if (!defaultRoles.includes(membership.role) && !hasPermission(permissions, permissionKey) && !hasPermission(templatePermissions, permissionKey)) {
    throw new HttpError(403, 'Tenant content permission is required', 'TENANT_CONTENT_PERMISSION_REQUIRED');
  }

  return { tenantId, userId, role: membership.role, permissions, templatePermissions };
}
