import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import { auditAction, auditCreate } from '@/features/foundation/audit-log/service';
import { getCustomerDetail } from '@/features/crm/customers/server/service';
import { opportunitySchema } from '@/features/crm/opportunities/schemas/opportunity.schema';
import { createOpportunity, listOpportunities } from '@/features/crm/opportunities/server/service';
import { PERMISSIONS } from '@/lib/auth/rbac';
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';

const opportunityRequestSchema = opportunitySchema.extend({
  contactId: z.string().nullable().optional(),
  assignedToUserId: z.string().nullable().optional(),
  branchId: z.string().nullable().optional(),
  leadChannel: z.string().nullable().optional(),
  expectedCloseDate: z.string().nullable().optional(),
  projectCloseDate: z.string().nullable().optional(),
  deliveryDate: z.string().nullable().optional()
});

function buildAccessContext(
  organizationId: string,
  sessionUserId: string,
  membership: Awaited<ReturnType<typeof requireOrganizationAccess>>['membership']
) {
  return {
    organizationId,
    userId: sessionUserId,
    membershipRole: membership.role,
    businessRole: membership.businessRole,
    permissions: membership.permissions ?? [],
    branchScopeIds: membership.branchScopeIds ?? [],
    productTypeScopeIds: membership.productTypeScopeIds ?? [],
    ownershipScope: membership.ownershipScope ?? 'organization',
    branchScopeMode: membership.branchScopeMode === 'assigned' ? 'assigned' : 'all',
    productScopeMode: membership.productScopeMode === 'assigned' ? 'assigned' : 'all'
  };
}

export async function GET(request: NextRequest) {
  try {
    const { organization, session, membership } = await requireOrganizationAccess({
      permission: PERMISSIONS.crmOpportunityRead
    });

    const { searchParams } = request.nextUrl;
    const accessContext = buildAccessContext(organization.id, session.user.id, membership);
    const page = Number(searchParams.get('page') ?? 1);
    const limit = Number(searchParams.get('limit') ?? 10);

    const result = await listOpportunities(accessContext, {
      page,
      limit,
      search: searchParams.get('search') ?? undefined,
      pipelineStage:
        (searchParams.get('pipelineStage') as 'lead' | 'opportunity' | 'closed_won' | 'closed_lost' | null) ??
        undefined,
      status: searchParams.get('status') ?? undefined,
      stage: searchParams.get('stage') ?? undefined,
      outcomeStatus: searchParams.get('outcomeStatus') ?? undefined,
      productType: searchParams.get('productType') ?? undefined,
      priority: searchParams.get('priority') ?? undefined,
      branch: searchParams.get('branch') ?? undefined,
      customer: searchParams.get('customer') ?? undefined,
      lostReason: searchParams.get('lostReason') ?? undefined,
      closedDateFrom: searchParams.get('closedDateFrom') ?? undefined,
      closedDateTo: searchParams.get('closedDateTo') ?? undefined,
      sort: searchParams.get('sort') ?? undefined
    });

    return NextResponse.json({
      success: true,
      time: new Date().toISOString(),
      message: 'Success',
      totalItems: result.totalItems,
      offset: (page - 1) * limit,
      limit,
      items: result.items
    });
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    if (error instanceof Error) {
      return NextResponse.json({ message: error.message }, { status: 400 });
    }

    return NextResponse.json({ message: 'Unable to list opportunities' }, { status: 500 });
  }
}

export async function POST(request: NextRequest) {
  try {
    const { organization, session, membership } = await requireOrganizationAccess({
      permission: PERMISSIONS.crmOpportunityCreate
    });

    const payload = opportunityRequestSchema.parse(await request.json());
    const accessContext = buildAccessContext(organization.id, session.user.id, membership);
    const created = await createOpportunity(organization.id, session.user.id, accessContext, payload);
    const customer = await getCustomerDetail(payload.customerId, organization.id);

    await auditCreate({
      organizationId: organization.id,
      branchId: created.branchId,
      userId: session.user.id,
      entityType: 'crm_opportunity',
      entityId: created.id,
      afterData: created
    });

    if (customer.ownerUserId) {
      await auditAction({
        organizationId: organization.id,
        branchId: created.branchId,
        userId: session.user.id,
        entityType: 'crm_opportunity',
        entityId: created.id,
        action:
          payload.assignedToUserId && payload.assignedToUserId !== customer.ownerUserId
            ? 'lead_owner_suggestion_overridden'
            : 'lead_owner_suggestion_used',
        afterData: {
          customerId: payload.customerId,
          suggestedOwnerUserId: customer.ownerUserId,
          assignedToUserId: payload.assignedToUserId ?? customer.ownerUserId
        }
      });
    }

    return NextResponse.json(
      {
        success: true,
        message: 'Opportunity created successfully',
        opportunity: created
      },
      { status: 201 }
    );
  } catch (error) {
    if (error instanceof AuthError) {
      return NextResponse.json({ message: error.message }, { status: error.status });
    }

    if (error instanceof z.ZodError) {
      return NextResponse.json(
        { message: error.issues[0]?.message ?? 'Invalid payload' },
        { status: 400 }
      );
    }

    if (error instanceof Error) {
      return NextResponse.json({ message: error.message }, { status: 400 });
    }

    return NextResponse.json({ message: 'Unable to create opportunity' }, { status: 500 });
  }
}
