import 'server-only';

import { and, count, eq, isNull } from 'drizzle-orm';
import {
  appNotificationTemplates,
  crmApprovalMatrices,
  crmApprovalWorkflows,
  crmReportDefinitions,
  crmRoleProfiles,
  crmUserRoleAssignments,
  documentSequences,
  memberships,
  msOptions,
  organizations,
  users
} from '@/db/schema';
import { getSetupPluginRegistry } from '@/features/setup/plugins/plugin-registry';
import { db } from '@/lib/db';
import type { SetupCheckResult, SetupVerificationReport } from '../api/types';
import {
  buildSetupCheck,
  buildSetupReport,
  checkEmailConfig,
  checkPdfMappingCoverage,
  checkPdfTemplateAsset
} from './readiness.service';

type VerificationInput = {
  organizationId?: string | null;
  administratorEmail?: string | null;
  profileId?: string | null;
};

function buildPluginVerificationChecks(profileId?: string | null): SetupCheckResult[] {
  return getSetupPluginRegistry()
    .resolveVerificationChecks(profileId ?? 'crm_demo')
    .map((check) =>
      buildSetupCheck(
        {
          id: check.id,
          area: check.area,
          name: check.name,
          requiredFor: check.requiredFor,
          purpose: check.purpose,
          suggestedFix: check.suggestedFix
        },
        'PASS',
        `${check.name} is registered by the setup plugin registry.`
      )
    );
}

async function resolveOrganizationId(input: VerificationInput): Promise<string | null> {
  if (input.organizationId) {
    const [organization] = await db
      .select({ id: organizations.id })
      .from(organizations)
      .where(eq(organizations.id, input.organizationId))
      .limit(1);
    return organization?.id ?? null;
  }
  return null;
}

async function resolveAdminUser(input: VerificationInput, organizationId: string | null) {
  if (input.administratorEmail) {
    const [user] = await db
      .select()
      .from(users)
      .where(eq(users.email, input.administratorEmail.trim().toLowerCase()))
      .limit(1);
    return user ?? null;
  }
  if (organizationId) {
    const [adminMembership] = await db
      .select({ user: users })
      .from(memberships)
      .innerJoin(users, eq(users.id, memberships.userId))
      .where(and(eq(memberships.organizationId, organizationId), eq(memberships.role, 'admin')))
      .limit(1);
    return adminMembership?.user ?? null;
  }
  const email = process.env.SUPER_ADMIN_EMAIL?.trim().toLowerCase();
  if (!email) return null;
  const [user] = await db.select().from(users).where(eq(users.email, email)).limit(1);
  return user ?? null;
}

async function countActiveOption(organizationId: string, category: string) {
  const [row] = await db
    .select({ value: count() })
    .from(msOptions)
    .where(
      and(
        eq(msOptions.organizationId, organizationId),
        eq(msOptions.category, category),
        eq(msOptions.isActive, true),
        isNull(msOptions.deletedAt)
      )
    );
  return Number(row?.value ?? 0);
}

async function countActiveSequences(organizationId: string, documentType: string) {
  const [row] = await db
    .select({ value: count() })
    .from(documentSequences)
    .where(
      and(
        eq(documentSequences.organizationId, organizationId),
        eq(documentSequences.documentType, documentType),
        eq(documentSequences.isActive, true)
      )
    );
  return Number(row?.value ?? 0);
}

export async function getSetupVerificationReport(
  input: VerificationInput
): Promise<SetupVerificationReport> {
  const organizationId = await resolveOrganizationId(input);
  const adminUser = await resolveAdminUser(input, organizationId);
  const checks: SetupCheckResult[] = [];

  checks.push(
    buildSetupCheck(
      {
        id: 'ADMIN_USER',
        area: 'Auth',
        name: 'First administrator exists',
        requiredFor: ['first login'],
        purpose: 'Ensure first login actor exists.',
        suggestedFix: 'Create administrator step.'
      },
      adminUser ? 'PASS' : 'FAIL',
      adminUser ? 'Administrator user exists.' : 'Administrator user was not found.',
      adminUser ? { email: adminUser.email } : undefined
    )
  );

  let adminMembershipRole: string | null = null;
  if (organizationId && adminUser) {
    const [membership] = await db
      .select()
      .from(memberships)
      .where(and(eq(memberships.organizationId, organizationId), eq(memberships.userId, adminUser.id)))
      .limit(1);
    adminMembershipRole = membership?.role ?? null;
  }
  checks.push(
    buildSetupCheck(
      {
        id: 'ADMIN_MEMBERSHIP',
        area: 'Auth',
        name: 'Administrator membership exists',
        requiredFor: ['first login'],
        purpose: 'Ensure admin can enter organization.',
        suggestedFix: 'Create membership.'
      },
      adminMembershipRole === 'admin' ? 'PASS' : adminMembershipRole ? 'WARNING' : 'FAIL',
      adminMembershipRole === 'admin'
        ? 'Administrator membership exists with admin role.'
        : adminMembershipRole
          ? 'Administrator membership exists but is not an admin role.'
          : 'Administrator membership was not found.',
      adminMembershipRole ? { role: adminMembershipRole } : undefined
    )
  );

  let crmAssignmentCount = 0;
  let legacyCrmAdmin = false;
  if (organizationId && adminUser) {
    const [assignmentRow] = await db
      .select({ value: count() })
      .from(crmUserRoleAssignments)
      .innerJoin(crmRoleProfiles, eq(crmRoleProfiles.id, crmUserRoleAssignments.roleProfileId))
      .where(
        and(
          eq(crmUserRoleAssignments.organizationId, organizationId),
          eq(crmUserRoleAssignments.userId, adminUser.id),
          eq(crmUserRoleAssignments.isActive, true),
          isNull(crmUserRoleAssignments.deletedAt),
          isNull(crmRoleProfiles.deletedAt),
          eq(crmRoleProfiles.code, 'crm_admin')
        )
      );
    crmAssignmentCount = Number(assignmentRow?.value ?? 0);
    const [membership] = await db
      .select({ businessRole: memberships.businessRole })
      .from(memberships)
      .where(and(eq(memberships.organizationId, organizationId), eq(memberships.userId, adminUser.id)))
      .limit(1);
    legacyCrmAdmin = membership?.businessRole === 'crm_admin';
  }
  checks.push(
    buildSetupCheck(
      {
        id: 'ADMIN_CRM_ASSIGNMENT',
        area: 'Authorization',
        name: 'Administrator CRM assignment resolves',
        requiredFor: ['CRM'],
        purpose: 'Ensure CRM admin permissions resolve.',
        suggestedFix: 'Seed role profiles and assignment.'
      },
      crmAssignmentCount > 0 ? 'PASS' : legacyCrmAdmin ? 'WARNING' : 'FAIL',
      crmAssignmentCount > 0
        ? 'CRM administrator role assignment exists.'
        : legacyCrmAdmin
          ? 'Only compatibility business role crm_admin was found.'
          : 'CRM administrator role assignment was not found.',
      { assignmentCount: crmAssignmentCount }
    )
  );

  const orgExists = Boolean(organizationId);
  const adminActiveOrgMatches = Boolean(adminUser && organizationId && adminUser.activeOrganizationId === organizationId);
  checks.push(
    buildSetupCheck(
      {
        id: 'ORG_ACTIVE',
        area: 'Organization',
        name: 'Organization active/resolvable',
        requiredFor: ['all setup'],
        purpose: 'Ensure active org context works.',
        suggestedFix: 'Update users.active_organization_id.'
      },
      orgExists && adminActiveOrgMatches ? 'PASS' : orgExists ? 'WARNING' : 'FAIL',
      orgExists && adminActiveOrgMatches
        ? 'Organization exists and is active for the administrator.'
        : orgExists
          ? 'Organization exists, but it is not the administrator active organization.'
          : 'Organization was not found.',
      { organizationId, adminActiveOrganizationId: adminUser?.activeOrganizationId ?? null }
    )
  );

  if (!organizationId) {
    const report = buildSetupReport(
      [...checks, ...buildPluginVerificationChecks(input.profileId)],
      'Setup verification checks completed.'
    );
    return { ...report, organizationId };
  }

  const branchCount = await countActiveOption(organizationId, 'crm_branch');
  checks.push(
    buildSetupCheck(
      {
        id: 'BRANCH_OPTION',
        area: 'Scope',
        name: 'Branch option exists',
        requiredFor: ['CRM/quotation'],
        purpose: 'Ensure branch scope can resolve.',
        suggestedFix: 'Configure branch step.'
      },
      branchCount > 0 ? 'PASS' : 'FAIL',
      branchCount > 0 ? 'Active branch options exist.' : 'No active branch option exists.',
      { count: branchCount }
    )
  );

  const productTypeCount = await countActiveOption(organizationId, 'crm_product_type');
  checks.push(
    buildSetupCheck(
      {
        id: 'PRODUCT_TYPE_OPTION',
        area: 'Scope',
        name: 'Product type option exists',
        requiredFor: ['CRM/quotation'],
        purpose: 'Ensure product scope can resolve.',
        suggestedFix: 'Configure product types.'
      },
      productTypeCount > 0 ? 'PASS' : 'FAIL',
      productTypeCount > 0 ? 'Active product type options exist.' : 'No active product type option exists.',
      { count: productTypeCount }
    )
  );

  const sequenceChecks = [
    ['SEQUENCE_CUSTOMER', 'Customer sequence preview', 'customer'],
    ['SEQUENCE_LEAD', 'Lead sequence preview', 'crm_lead'],
    ['SEQUENCE_OPPORTUNITY', 'Opportunity sequence preview', 'crm_opportunity'],
    ['SEQUENCE_QUOTATION', 'Quotation sequence preview', 'quotation']
  ] as const;
  for (const [id, name, documentType] of sequenceChecks) {
    const sequenceCount = await countActiveSequences(organizationId, documentType);
    checks.push(
      buildSetupCheck(
        {
          id,
          area: 'Document sequence',
          name,
          requiredFor: documentType === 'quotation' ? ['quotation'] : ['CRM'],
          purpose: `Ensure ${documentType} codes can generate.`,
          suggestedFix: 'Configure document sequence.'
        },
        sequenceCount > 0 ? 'PASS' : 'FAIL',
        sequenceCount > 0
          ? `Active ${documentType} sequence exists.`
          : `No active ${documentType} sequence exists.`,
        { documentType, count: sequenceCount }
      )
    );
  }

  const [workflowRow] = await db
    .select({ value: count() })
    .from(crmApprovalWorkflows)
    .where(
      and(
        eq(crmApprovalWorkflows.organizationId, organizationId),
        eq(crmApprovalWorkflows.entityType, 'quotation'),
        eq(crmApprovalWorkflows.isActive, true),
        isNull(crmApprovalWorkflows.deletedAt)
      )
    );
  const workflowCount = Number(workflowRow?.value ?? 0);
  checks.push(
    buildSetupCheck(
      {
        id: 'APPROVAL_WORKFLOW',
        area: 'Approval',
        name: 'Quotation workflow resolves',
        requiredFor: ['quotation'],
        purpose: 'Ensure quotation approval can start.',
        suggestedFix: 'Configure approval workflow.'
      },
      workflowCount === 1 ? 'PASS' : workflowCount > 1 ? 'WARNING' : 'FAIL',
      workflowCount === 1
        ? 'One active quotation approval workflow exists.'
        : workflowCount > 1
          ? 'Multiple active quotation approval workflows exist.'
          : 'No active quotation approval workflow exists.',
      { count: workflowCount }
    )
  );

  const [matrixRow] = await db
    .select({ value: count() })
    .from(crmApprovalMatrices)
    .where(
      and(
        eq(crmApprovalMatrices.organizationId, organizationId),
        eq(crmApprovalMatrices.entityType, 'quotation'),
        eq(crmApprovalMatrices.isActive, true),
        isNull(crmApprovalMatrices.deletedAt)
      )
    );
  const matrixCount = Number(matrixRow?.value ?? 0);
  checks.push(
    buildSetupCheck(
      {
        id: 'APPROVAL_MATRIX',
        area: 'Approval',
        name: 'Approval matrix resolves',
        requiredFor: ['quotation'],
        purpose: 'Ensure quotation can select workflow by scope/amount.',
        suggestedFix: 'Configure approval matrix.'
      },
      matrixCount > 0 ? 'PASS' : 'FAIL',
      matrixCount > 0 ? 'Active quotation approval matrix rows exist.' : 'No active quotation approval matrix exists.',
      { count: matrixCount }
    )
  );

  checks.push(await checkPdfTemplateAsset(organizationId));
  checks.push(await checkPdfMappingCoverage(organizationId));

  const [notificationRow] = await db
    .select({ value: count() })
    .from(appNotificationTemplates)
    .where(
      and(
        eq(appNotificationTemplates.organizationId, organizationId),
        eq(appNotificationTemplates.channel, 'in_app'),
        eq(appNotificationTemplates.isActive, true),
        isNull(appNotificationTemplates.deletedAt)
      )
    );
  const notificationCount = Number(notificationRow?.value ?? 0);
  checks.push(
    buildSetupCheck(
      {
        id: 'NOTIFICATION_TEMPLATES',
        area: 'Notifications',
        name: 'Approval notification templates exist',
        requiredFor: ['CRM/quotation'],
        purpose: 'Ensure in-app approval notifications can render.',
        suggestedFix: 'Run foundation seed.'
      },
      notificationCount > 0 ? 'PASS' : 'FAIL',
      notificationCount > 0
        ? 'Active in-app notification templates exist.'
        : 'No active in-app notification template exists.',
      { count: notificationCount }
    )
  );

  const [reportRow] = await db
    .select({ value: count() })
    .from(crmReportDefinitions)
    .where(
      and(
        eq(crmReportDefinitions.organizationId, organizationId),
        eq(crmReportDefinitions.isActive, true)
      )
    );
  const reportCount = Number(reportRow?.value ?? 0);
  checks.push(
    buildSetupCheck(
      {
        id: 'REPORT_DEFINITIONS',
        area: 'Reports',
        name: 'Report definitions exist',
        requiredFor: ['CRM reports'],
        purpose: 'Ensure report catalog works.',
        suggestedFix: 'Run report foundation seed.'
      },
      reportCount > 0 ? 'PASS' : 'FAIL',
      reportCount > 0 ? 'Active report definitions exist.' : 'No active report definitions exist.',
      { count: reportCount }
    )
  );

  checks.push(await checkEmailConfig(organizationId));

  checks.push(
    buildSetupCheck(
      {
        id: 'CSV_PREVIEW',
        area: 'Import',
        name: 'CSV preview integrity',
        requiredFor: ['CSV import'],
        purpose: 'Ensure uploaded files were validated before commit.',
        suggestedFix: 'Re-run CSV preview.'
      },
      'WARNING',
      'CSV preview tracking is planned for a later setup import slice.'
    )
  );

  checks.push(
    buildSetupCheck(
      {
        id: 'SETUP_MANIFEST',
        area: 'Setup',
        name: 'Seed manifest recorded',
        requiredFor: ['setup completion'],
        purpose: 'Ensure lifecycle tracking exists.',
        suggestedFix: 'Implement D.7.8.'
      },
      'WARNING',
      'Seed manifest persistence is planned for D.7.8.'
    )
  );

  const report = buildSetupReport(
    [...checks, ...buildPluginVerificationChecks(input.profileId)],
    'Setup verification checks completed.'
  );
  return { ...report, organizationId };
}
