import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod/v3';
import type { ValuationDeps } from '../shared/types';

const PROPERTY_TYPES = ['apartment', 'house', 'townhouse', 'villa', 'land', 'shophouse'] as const;

interface AVMResponse {
  estimated_price_vnd: number;
  confidence: number;
  price_per_m2: number;
  price_range_low: number;
  price_range_high: number;
}

interface FeatureExtractResponse {
  features?: {
    area?: number;
    district?: string;
    city?: string;
    property_type?: string;
    bedrooms?: number;
    bathrooms?: number;
    floors?: number;
    frontage?: number;
    road_width?: number;
    price_mentioned?: number;
    has_legal_paper?: boolean;
  };
  tokens?: string[];
  entities?: { text: string; label: string }[];
}

const EstimateValueSchema = {
  area: z.number().positive().describe('Property area in m²'),
  district: z.string().min(1).describe('District name'),
  city: z.string().min(1).describe('City name'),
  propertyType: z.enum(PROPERTY_TYPES).describe('Property type'),
  bedrooms: z.number().int().min(0).default(0),
  bathrooms: z.number().int().min(0).default(0),
  floors: z.number().int().min(0).default(0),
  frontage: z.number().min(0).default(0).describe('Frontage width in meters'),
  roadWidth: z.number().min(0).default(0).describe('Adjacent road width in meters'),
  yearBuilt: z.number().int().optional().describe('Year the property was built'),
  hasLegalPaper: z.boolean().default(true).describe('Has sổ đỏ/sổ hồng'),
};

const ExtractFeaturesSchema = {
  text: z.string().min(1).describe('Vietnamese property listing text to analyze'),
};

const BatchValuationSchema = {
  properties: z.array(z.object({
    area: z.number().positive(),
    district: z.string().min(1),
    city: z.string().min(1),
    propertyType: z.enum(PROPERTY_TYPES),
    bedrooms: z.number().int().min(0).default(0),
    bathrooms: z.number().int().min(0).default(0),
    floors: z.number().int().min(0).default(0),
    frontage: z.number().min(0).default(0),
    roadWidth: z.number().min(0).default(0),
    yearBuilt: z.number().int().optional(),
    hasLegalPaper: z.boolean().default(true),
  })).min(1).max(20).describe('Array of properties to valuate'),
};

async function callAVM(baseUrl: string, body: Record<string, unknown>): Promise<{ data?: AVMResponse; error?: string }> {
  const response = await fetch(`${baseUrl}/avm/predict`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    const errorText = await response.text();
    return { error: `AVM service error (${response.status}): ${errorText}` };
  }

  const data = (await response.json()) as AVMResponse;
  return { data };
}

export function createValuationServer(deps: ValuationDeps): McpServer {
  const baseUrl = deps.aiServiceBaseUrl.replace(/\/$/, '');

  const server = new McpServer({
    name: 'goodgo-valuation',
    version: '0.1.0',
  });

  server.tool(
    'estimate_property_value',
    "Estimate a property's market value using the AVM. Returns price, confidence, and range.",
    EstimateValueSchema,
    async (params: z.infer<z.ZodObject<typeof EstimateValueSchema>>) => {
      const body = {
        area: params.area,
        district: params.district,
        city: params.city,
        property_type: params.propertyType,
        bedrooms: params.bedrooms,
        bathrooms: params.bathrooms,
        floors: params.floors,
        frontage: params.frontage,
        road_width: params.roadWidth,
        year_built: params.yearBuilt ?? null,
        has_legal_paper: params.hasLegalPaper,
      };

      const { data, error } = await callAVM(baseUrl, body);
      if (error || !data) {
        return {
          content: [{ type: 'text' as const, text: JSON.stringify({ error }) }],
          isError: true,
        };
      }

      return {
        content: [{
          type: 'text' as const,
          text: JSON.stringify({
            estimatedPriceVND: data.estimated_price_vnd,
            confidence: data.confidence,
            pricePerM2: data.price_per_m2,
            priceRangeLow: data.price_range_low,
            priceRangeHigh: data.price_range_high,
            input: { area: params.area, district: params.district, city: params.city, propertyType: params.propertyType },
          }, null, 2),
        }],
      };
    },
  );

  server.tool(
    'extract_listing_features',
    'Extract real estate features from Vietnamese listing text using NLP.',
    ExtractFeaturesSchema,
    async (params: z.infer<z.ZodObject<typeof ExtractFeaturesSchema>>) => {
      const response = await fetch(`${baseUrl}/avm/extract-features`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ text: params.text }),
      });

      if (!response.ok) {
        const errorText = await response.text();
        return {
          content: [{
            type: 'text' as const,
            text: JSON.stringify({ error: `Feature extraction error (${response.status}): ${errorText}` }),
          }],
          isError: true,
        };
      }

      const result = (await response.json()) as FeatureExtractResponse;

      return {
        content: [{
          type: 'text' as const,
          text: JSON.stringify({
            features: {
              area: result.features?.area ?? null,
              district: result.features?.district ?? null,
              city: result.features?.city ?? null,
              propertyType: result.features?.property_type ?? null,
              bedrooms: result.features?.bedrooms ?? null,
              bathrooms: result.features?.bathrooms ?? null,
              floors: result.features?.floors ?? null,
              frontage: result.features?.frontage ?? null,
              roadWidth: result.features?.road_width ?? null,
              priceMentioned: result.features?.price_mentioned ?? null,
              hasLegalPaper: result.features?.has_legal_paper ?? null,
            },
            tokens: result.tokens ?? [],
            entities: result.entities ?? [],
          }, null, 2),
        }],
      };
    },
  );

  server.tool(
    'batch_valuation',
    'Estimate values for multiple properties at once for portfolio or investment analysis.',
    BatchValuationSchema,
    async (params: z.infer<z.ZodObject<typeof BatchValuationSchema>>) => {
      const results = await Promise.all(
        params.properties.map(async (prop, index) => {
          const body = {
            area: prop.area,
            district: prop.district,
            city: prop.city,
            property_type: prop.propertyType,
            bedrooms: prop.bedrooms,
            bathrooms: prop.bathrooms,
            floors: prop.floors,
            frontage: prop.frontage,
            road_width: prop.roadWidth,
            year_built: prop.yearBuilt ?? null,
            has_legal_paper: prop.hasLegalPaper,
          };

          try {
            const { data, error } = await callAVM(baseUrl, body);
            if (error || !data) return { index, input: prop, error };
            return {
              index,
              input: { area: prop.area, district: prop.district, city: prop.city, propertyType: prop.propertyType },
              valuation: {
                estimatedPriceVND: data.estimated_price_vnd,
                confidence: data.confidence,
                pricePerM2: data.price_per_m2,
                priceRangeLow: data.price_range_low,
                priceRangeHigh: data.price_range_high,
              },
            };
          } catch (err) {
            return { index, input: prop, error: String(err) };
          }
        }),
      );

      return {
        content: [{
          type: 'text' as const,
          text: JSON.stringify({ valuations: results }, null, 2),
        }],
      };
    },
  );

  return server;
}
