import { formatABN } from "@/lib/abn-utils";
import { NextRequest, NextResponse } from 'next/server';
import { isValidABN, cleanABN } from '@/lib/abn-utils';
import { checkRateLimit, getClientIP, createRateLimitResponse } from '@/lib/rate-limit';
import { sanitizeInput } from '@/lib/sanitize';
import { z } from 'zod';
import { 
  MAX_LENGTH_EMAIL,
  TIMEOUT_ABN_LOOKUP,
  POSTCODE_SYDNEY,
  POSTCODE_MELBOURNE 
} from '@/lib/constants';
import { getCachedABN, cacheABNData } from '@/lib/abn-cache';
import { logger } from '@/lib/logger';

/**
 * ABN Lookup API Route — GET /api/abn-lookup?abn=XXXXXXXXXXX
 *
 * Validates the ABN locally (checksum), then calls the ABR JSON endpoint
 * to fetch entity details.
 *
 * ABR JSON docs: https://abr.business.gov.au/json/
 * Registration:  https://abr.business.gov.au/Tools/WebServices
 *
 * Required env var:
 *   ABR_GUID — the authentication GUID issued after registration
 *
 * Optional env var:
 *   ABR_DEV_MODE — set to 'true' to enable development mode with mock data
 */

// ── ABR configuration ──────────────────────────────────────────────
const ABR_JSON_URL = 'https://abr.business.gov.au/json/AbnDetails.aspx';
const ABR_GUID = process.env.ABR_GUID ?? '';
const ABR_DEV_MODE = process.env.ABR_DEV_MODE === 'true';

// ── Types ──────────────────────────────────────────────────────────

/** Shape returned by the ABR JSON endpoint (JSONP-unwrapped). */
interface ABRJsonResponse {
  Abn: string;
  AbnStatus: string;
  AbnStatusEffectiveFrom: string;
  Acn: string;
  AddressDate: string | null;
  AddressPostcode: string;
  AddressState: string;
  BusinessName: Array<string | { Value: string; EffectiveFrom: string }>;
  EntityName: string;
  EntityTypeCode: string;
  EntityTypeName: string;
  Gst: string | null;
  Message: string;
}

/** Director verification result */
interface DirectorVerification {
  status: 'pending' | 'verified' | 'mismatch' | 'not_available' | 'auto_verified' | 'manual_review';
  message: string;
  requiresManualReview?: boolean;
  verificationMethod?: string;
  riskScore?: number;
  riskFactors?: string[];
}

/** Company data from ABR */
interface CompanyData {
  name: string;
  abn: string;
  status: string;
  statusDate: string;
  state: string;
  postcode: string;
  type: string;
  typeCode: string;
  gstRegistered: boolean;
  acn?: string;
  directorVerification?: DirectorVerification;
}

/** Our normalised response. */
interface ABNLookupResult {
  success: boolean;
  data?: CompanyData;
  error?: string;
  devMode?: boolean;
}

// ── Development Mode Mock Data ─────────────────────────────────────

/**
 * Mock company data for development when ABR_GUID is not configured.
 * Uses obviously fake ABNs to prevent confusion with real data.
 */
const MOCK_COMPANIES: Record<string, CompanyData> = {
  // Test ABN for development - passes checksum but is obviously fake
  '51824753556': {
    name: 'TEST COMPANY PTY LTD (Dev Mode)',
    abn: '51 824 753 556',
    status: 'Active',
    statusDate: '2020-01-01',
    state: 'NSW',
    postcode: POSTCODE_SYDNEY,
    type: 'Australian Private Company',
    typeCode: 'PRV',
    gstRegistered: true,
    directorVerification: {
      status: 'auto_verified',
      message: 'Development mode - auto-verified',
      verificationMethod: 'dev_mode',
      riskScore: 0,
    },
  },
  // Another test ABN
  '34241177887': {
    name: 'EXAMPLE BUILDERS PTY LTD (Dev Mode)',
    abn: '34 241 177 887',
    status: 'Active',
    statusDate: '2019-06-15',
    state: 'VIC',
    postcode: POSTCODE_MELBOURNE,
    type: 'Australian Private Company',
    typeCode: 'PRV',
    gstRegistered: true,
    directorVerification: {
      status: 'auto_verified',
      message: 'Development mode - auto-verified',
      verificationMethod: 'dev_mode',
      riskScore: 0,
    },
  },
};

/**
 * Generate mock data for any valid ABN in development mode.
 */
function generateMockData(abn: string): CompanyData {
  const formatted = formatABN(abn);
  return {
    name: `MOCK COMPANY ${abn.slice(-4)} PTY LTD (Dev Mode)`,
    abn: formatted,
    status: 'Active',
    statusDate: new Date().toISOString().split('T')[0],
    state: 'NSW',
    postcode: POSTCODE_SYDNEY,
    type: 'Australian Private Company',
    typeCode: 'PRV',
    gstRegistered: Math.random() > 0.3,
    directorVerification: {
      status: 'auto_verified',
      message: 'Development mode - auto-verified',
      verificationMethod: 'dev_mode',
      riskScore: 0,
    },
  };
}

// ── Helpers ────────────────────────────────────────────────────────

function buildABRUrl(abn: string): string {
  const params = new URLSearchParams({
    abn,
    guid: ABR_GUID,
    callback: 'cbr',
  });
  return `${ABR_JSON_URL}?${params.toString()}`;
}

function stripJSONP(jsonp: string): ABRJsonResponse {
  const match = jsonp.match(/^cbr\((.*)\)$/);
  if (!match) throw new Error('Unexpected ABR response format');
  return JSON.parse(match[1]);
}

function normaliseABRResponse(abr: ABRJsonResponse): CompanyData {
  const name = abr.EntityName ||
    (Array.isArray(abr.BusinessName) && abr.BusinessName[0]) ||
    'Unknown';

  return {
    name: typeof name === 'string' ? name : (name as any).Value || 'Unknown',
    abn: formatABN(abr.Abn),
    status: abr.AbnStatus,
    statusDate: abr.AbnStatusEffectiveFrom,
    state: abr.AddressState,
    postcode: abr.AddressPostcode,
    type: abr.EntityTypeName,
    typeCode: abr.EntityTypeCode,
    gstRegistered: abr.Gst !== null,
    acn: abr.Acn || undefined,
    // Director verification will be done by verifyDirector() function
  };
}

/**
 * Multi-Layer Director Verification
 *
 * Implements a practical 3-tier verification system:
 * 1. Automated checks (email domain, GST status, entity type)
 * 2. Risk scoring to flag suspicious registrations
 * 3. Manual review fallback for high-risk cases
 *
 * Future: ASIC Connect API integration for real director lookup
 * @see https://connectonline.asic.gov.au/
 */
async function verifyDirector(
  abn: string,
  companyData: CompanyData,
  userEmail?: string
): Promise<DirectorVerification> {
  const riskFactors: string[] = [];
  let riskScore = 0;

  // --- Layer 1: Automated Verification Checks ---

  // Check 1: GST Registration (legitimate businesses usually have GST)
  if (!companyData.gstRegistered) {
    riskScore += 15;
    riskFactors.push('Not GST registered');
  }

  // Check 2: Entity Type (only allow private companies and sole traders)
  const allowedEntityTypes = ['PRV', 'IND']; // Private Company, Individual/Sole Trader
  if (!allowedEntityTypes.includes(companyData.typeCode)) {
    riskScore += 30;
    riskFactors.push(`Unusual entity type: ${companyData.type}`);
  }

  // Check 3: ABN Status (must be active)
  if (companyData.status.toLowerCase() !== 'active') {
    riskScore += 50;
    riskFactors.push(`ABN status: ${companyData.status}`);
  }

  // Check 4: Email Domain Validation (if provided)
  if (userEmail) {
    const emailDomain = userEmail.split('@')[1]?.toLowerCase();
    const companyName = companyData.name.toLowerCase();

    // Check if email is free provider (gmail, outlook, etc.)
    const freeEmailProviders = [
      'gmail.com', 'outlook.com', 'hotmail.com', 'yahoo.com',
      'icloud.com', 'live.com', 'msn.com', 'protonmail.com'
    ];

    if (freeEmailProviders.includes(emailDomain)) {
      riskScore += 20;
      riskFactors.push('Using free email provider (no company domain)');
    } else {
      // Check if email domain roughly matches company name
      const domainParts = emailDomain.replace(/\.com\.au|\.com|\.net\.au|\.net|\.org\.au|\.org/g, '').split('.');
      const companyParts = companyName.replace(/pty ltd|pty|ltd|limited|proprietary/gi, '').trim().split(/\s+/);

      // Simple fuzzy match: check if any significant word from company name is in domain
      const hasMatch = companyParts.some(part =>
        part.length > 3 && domainParts.some(dp =>
          dp.includes(part.toLowerCase()) || part.toLowerCase().includes(dp)
        )
      );

      if (!hasMatch) {
        riskScore += 25;
        riskFactors.push('Email domain does not match company name');
      }
    }
  } else {
    // No email provided for verification
    riskScore += 10;
    riskFactors.push('No email provided for verification');
  }

  // Check 5: Company Age (ABN status date - newly registered companies are riskier)
  const statusDate = new Date(companyData.statusDate);
  const monthsOld = (Date.now() - statusDate.getTime()) / (1000 * 60 * 60 * 24 * 30);

  if (monthsOld < 3) {
    riskScore += 20;
    riskFactors.push('Company registered less than 3 months ago');
  } else if (monthsOld < 12) {
    riskScore += 10;
    riskFactors.push('Company registered less than 1 year ago');
  }

  // Check 6: Missing ACN (private companies should have ACN)
  if (companyData.typeCode === 'PRV' && !companyData.acn) {
    riskScore += 15;
    riskFactors.push('Private company missing ACN');
  }

  // --- Layer 2: Risk Score Evaluation ---

  // Low Risk (0-25): Auto-verify
  if (riskScore <= 25 && companyData.status.toLowerCase() === 'active') {
    return {
      status: 'auto_verified',
      message: 'Company automatically verified based on ABR data and basic checks',
      verificationMethod: 'automated',
      riskScore,
      riskFactors: riskFactors.length > 0 ? riskFactors : undefined,
      requiresManualReview: false,
    };
  }

  // Medium Risk (26-50): Flag for manual review but allow signup
  if (riskScore <= 50) {
    return {
      status: 'manual_review',
      message: 'Company registration flagged for manual review. You can proceed with signup.',
      verificationMethod: 'manual_review_required',
      riskScore,
      riskFactors,
      requiresManualReview: true,
    };
  }

  // High Risk (51+): Require manual approval before activation
  return {
    status: 'pending',
    message: 'Company registration requires manual verification before activation. Our team will review within 24 hours.',
    verificationMethod: 'manual_approval_required',
    riskScore,
    riskFactors,
    requiresManualReview: true,
  };
}

// ── Route Handler ──────────────────────────────────────────────────

// Rate limit: 10 requests per 15 minutes per IP (external API call)
const ABN_LOOKUP_RATE_LIMIT = 10;
const ABN_LOOKUP_WINDOW_MS = 15 * 60 * 1000;

// Email validation schema
const emailSchema = z.string().email().max(254);

export async function GET(request: NextRequest) {
  try {
    // --- 0. Rate limiting ---------------------------------------------------
    const clientIP = getClientIP(request);
    const rateLimit = await checkRateLimit(`abn-lookup:${clientIP}`, ABN_LOOKUP_RATE_LIMIT, ABN_LOOKUP_WINDOW_MS);
    
    if (!rateLimit.allowed) {
      const retryAfter = Math.ceil((rateLimit.resetTime - Date.now()) / 1000);
      return createRateLimitResponse(clientIP, retryAfter);
    }
    
    const searchParams = request.nextUrl.searchParams;
    const rawABN = searchParams.get('abn');
    const rawEmail = searchParams.get('email');

    // --- 1. Validate input --------------------------------------------------
    if (!rawABN) {
      return NextResponse.json({
        success: false,
        error: 'Missing query parameter: abn'
      }, { status: 400 });
    }

    const abn = cleanABN(rawABN);
    if (!isValidABN(abn)) {
      return NextResponse.json({
        success: false,
        error: 'Invalid ABN format. Please check the number and try again.'
      }, { status: 400 });
    }

    // Validate email format if provided
    let userEmail: string | null = null;
    if (rawEmail) {
      const sanitizedEmail = sanitizeInput(rawEmail, { maxLength: MAX_LENGTH_EMAIL });
      const emailValidation = emailSchema.safeParse(sanitizedEmail);

      if (!emailValidation.success) {
        return NextResponse.json({
          success: false,
          error: 'Invalid email format. Please provide a valid email address.'
        }, { status: 400 });
      }

      userEmail = emailValidation.data;
    }

    // --- 2. Check cache first ----------------------------------------------
    const cachedData = await getCachedABN(abn);
    if (cachedData) {
      logger.info(`[ABN Lookup] Cache hit for ABN: ${abn}`);
      
      // Convert cached data to the expected format
      const result: CompanyData & { directorVerification?: DirectorVerification } = {
        name: cachedData.companyName,
        abn: cachedData.abn,
        status: cachedData.status,
        statusDate: cachedData.statusDate || '',
        state: cachedData.state || '',
        postcode: cachedData.postcode || '',
        type: cachedData.entityType || '',
        typeCode: cachedData.entityTypeCode || '',
        gstRegistered: cachedData.gstRegistered || false,
        acn: cachedData.acn,
      };
      
      // Director verification (same as before)
      result.directorVerification = await verifyDirector(
        abn,
        result,
        userEmail || undefined
      );
      
      return NextResponse.json({
        success: true,
        data: result,
        cached: true,
        cachedAt: cachedData.cachedAt,
      });
    }
    
    logger.info(`[ABN Lookup] Cache miss for ABN: ${abn}, calling ABR API`);

    // --- 3. Check if ABR_GUID is configured --------------------------------
    const isGuidConfigured = ABR_GUID && 
      ABR_GUID !== 'REGISTER-TOMORROW-AT-ABR-BUSINESS-GOV-AU' &&
      ABR_GUID !== 'temporary-abr-guid-for-build';

    if (!isGuidConfigured) {
      // Development mode: return mock data
      if (ABR_DEV_MODE) {
        logger.info(`[ABN Lookup] Dev mode - returning mock data for ${abn}`);
        const mockData = MOCK_COMPANIES[abn] || generateMockData(abn);
        return NextResponse.json({
          success: true,
          data: mockData,
          devMode: true,
        });
      }

      // Production without GUID: return error with validation info
      return NextResponse.json({
        success: false,
        error: 'ABR service not configured',
        devMode: false,
      }, { status: 503 });
    }

    // --- 4. Call ABR web service -------------------------------------------
    const url = buildABRUrl(abn);
    const abrResponse = await fetch(url, {
      method: 'GET',
      headers: { 'User-Agent': 'RateRight/1.0' },
      signal: AbortSignal.timeout(TIMEOUT_ABN_LOOKUP),
    });

    if (!abrResponse.ok) {
      const text = await abrResponse.text();
      logger.error(`[ABN Lookup] ABR error ${abrResponse.status}:`, text);
      return NextResponse.json({
        success: false,
        error: `ABR service error: ${abrResponse.status}`,
      }, { status: 502 });
    }

    const jsonpText = await abrResponse.text();
    const abrData = stripJSONP(jsonpText);

    // --- 5. Handle ABR business logic ---------------------------------------
    if (abrData.Message) {
      // Cache the "not found" result with shorter expiry
      await cacheABNData({
        abn: abn,
        companyName: 'Not Found',
        status: 'Not Found',
        abrResponse: abrData,
      });
      
      return NextResponse.json({ 
        success: false, 
        error: abrData.Message 
      }, { status: 404 });
    }

    const result: CompanyData & { directorVerification?: DirectorVerification } = normaliseABRResponse(abrData);
    
    // Cache the successful result
    await cacheABNData({
      abn: result.abn,
      companyName: result.name,
      status: result.status,
      statusDate: result.statusDate,
      state: result.state,
      postcode: result.postcode,
      entityType: result.type,
      entityTypeCode: result.typeCode,
      gstRegistered: result.gstRegistered,
      acn: result.acn,
      abrResponse: abrData,
    });

    // --- 5. Director verification (multi-layer automated + risk scoring) ----
    result.directorVerification = await verifyDirector(
      abn,
      result,
      userEmail || undefined
    );

    return NextResponse.json({
      success: true,
      data: result,
    });

  } catch (err: unknown) {
    logger.error('[ABN Lookup] Uncaught error:', err);
    return NextResponse.json({
      success: false,
      error: 'Internal server error',
    }, { status: 500 });
  }
}
