import { McpServer } from '@modelcontextprotocol/sdk/server/mcp';
import { z } from 'zod';
import { canAccessTrip } from '../../db/database';
import { isDemoUser } from '../../services/authService';
import {
  createReservation, deleteReservation, getReservation, updateReservation,
} from '../../services/reservationService';
import { getDay } from '../../services/dayService';
import {
  safeBroadcast, TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
  TOOL_ANNOTATIONS_WRITE, demoDenied, noAccess, ok,
} from './_shared';
import { canWrite } from '../scopes';

const TRANSPORT_TYPES = ['flight', 'train', 'car', 'cruise'] as const;

const endpointSchema = z.array(z.object({
  role: z.enum(['from', 'to', 'stop']).describe('Endpoint role: "from" (origin), "to" (destination), or "stop" (intermediate)'),
  sequence: z.number().int().min(0).describe('Order within the route (0-based)'),
  name: z.string().min(1).describe('Location name (e.g. "Paris Gare de Lyon", "ZRH Terminal 2")'),
  code: z.string().optional().describe('IATA airport code for flights (e.g. "ZRH"). Leave empty for other transport types.'),
  lat: z.number().optional(),
  lng: z.number().optional(),
  timezone: z.string().optional().describe('IANA timezone (e.g. "Europe/Zurich"). Use airport tz for flights.'),
  local_time: z.string().optional().describe('Local departure/arrival time at this endpoint, e.g. "14:35"'),
  local_date: z.string().optional().describe('Local date at this endpoint, YYYY-MM-DD'),
})).optional();

export function registerTransportTools(server: McpServer, userId: number, scopes: string[] | null): void {
  if (!canWrite(scopes, 'reservations')) return;

  server.registerTool(
    'create_transport',
    {
      description: 'Create a transport booking (flight, train, car, or cruise) for a trip. Use endpoints[] to record origin/destination and intermediate stops — for flights, set code to the IATA airport code (use search_airports first). Created as pending — confirm with update_transport.',
      inputSchema: {
        tripId: z.number().int().positive(),
        type: z.enum(['flight', 'train', 'car', 'cruise']),
        title: z.string().min(1).max(200),
        status: z.enum(['pending', 'confirmed', 'cancelled']).optional().default('pending'),
        start_day_id: z.number().int().positive().optional().describe('Departure day'),
        end_day_id: z.number().int().positive().optional().describe('Arrival day (if different from departure)'),
        reservation_time: z.string().optional().describe('ISO 8601 datetime or time string for departure'),
        reservation_end_time: z.string().optional().describe('ISO 8601 datetime or time string for arrival'),
        confirmation_number: z.string().max(100).optional(),
        notes: z.string().max(1000).optional(),
        metadata: z.record(z.string(), z.string()).optional().describe('Type-specific metadata: flights → { airline, flight_number, departure_airport, arrival_airport }; trains → { train_number, platform, seat }'),
        endpoints: endpointSchema,
        needs_review: z.boolean().optional(),
      },
      annotations: TOOL_ANNOTATIONS_NON_IDEMPOTENT,
    },
    async ({ tripId, type, title, status, start_day_id, end_day_id, reservation_time, reservation_end_time, confirmation_number, notes, metadata, endpoints, needs_review }) => {
      if (isDemoUser(userId)) return demoDenied();
      if (!canAccessTrip(tripId, userId)) return noAccess();

      if (start_day_id && !getDay(start_day_id, tripId))
        return { content: [{ type: 'text' as const, text: 'start_day_id does not belong to this trip.' }], isError: true };
      if (end_day_id && !getDay(end_day_id, tripId))
        return { content: [{ type: 'text' as const, text: 'end_day_id does not belong to this trip.' }], isError: true };

      const { reservation } = createReservation(tripId, {
        title,
        type,
        reservation_time,
        reservation_end_time,
        location: undefined,
        confirmation_number,
        notes,
        day_id: start_day_id,
        end_day_id: end_day_id ?? start_day_id,
        status: status ?? 'pending',
        metadata,
        endpoints,
        needs_review,
      });
      safeBroadcast(tripId, 'reservation:created', { reservation });
      return ok({ reservation });
    }
  );

  server.registerTool(
    'update_transport',
    {
      description: 'Update an existing transport booking. Pass endpoints[] to replace the full list of stops (origin, destination, intermediates). Use status "confirmed" to confirm.',
      inputSchema: {
        tripId: z.number().int().positive(),
        reservationId: z.number().int().positive(),
        type: z.enum(['flight', 'train', 'car', 'cruise']).optional(),
        title: z.string().min(1).max(200).optional(),
        status: z.enum(['pending', 'confirmed', 'cancelled']).optional(),
        start_day_id: z.number().int().positive().optional().describe('Departure day'),
        end_day_id: z.number().int().positive().optional().describe('Arrival day (if different from departure)'),
        reservation_time: z.string().optional().describe('ISO 8601 datetime or time string for departure'),
        reservation_end_time: z.string().optional().describe('ISO 8601 datetime or time string for arrival'),
        confirmation_number: z.string().max(100).optional(),
        notes: z.string().max(1000).optional(),
        metadata: z.record(z.string(), z.string()).optional().describe('Type-specific metadata: flights → { airline, flight_number, departure_airport, arrival_airport }; trains → { train_number, platform, seat }'),
        endpoints: endpointSchema,
        needs_review: z.boolean().optional(),
      },
      annotations: TOOL_ANNOTATIONS_WRITE,
    },
    async ({ tripId, reservationId, type, title, status, start_day_id, end_day_id, reservation_time, reservation_end_time, confirmation_number, notes, metadata, endpoints, needs_review }) => {
      if (isDemoUser(userId)) return demoDenied();
      if (!canAccessTrip(tripId, userId)) return noAccess();

      const existing = getReservation(reservationId, tripId);
      if (!existing) return { content: [{ type: 'text' as const, text: 'Transport not found.' }], isError: true };

      const resolvedType = type ?? existing.type;
      if (!(TRANSPORT_TYPES as readonly string[]).includes(resolvedType))
        return { content: [{ type: 'text' as const, text: 'Reservation is not a transport type. Use update_reservation instead.' }], isError: true };

      if (start_day_id && !getDay(start_day_id, tripId))
        return { content: [{ type: 'text' as const, text: 'start_day_id does not belong to this trip.' }], isError: true };
      if (end_day_id && !getDay(end_day_id, tripId))
        return { content: [{ type: 'text' as const, text: 'end_day_id does not belong to this trip.' }], isError: true };

      const { reservation } = updateReservation(reservationId, tripId, {
        title,
        type,
        reservation_time,
        reservation_end_time,
        confirmation_number,
        notes,
        day_id: start_day_id,
        end_day_id,
        status,
        metadata,
        endpoints,
        needs_review,
      }, existing);
      safeBroadcast(tripId, 'reservation:updated', { reservation });
      return ok({ reservation });
    }
  );

  server.registerTool(
    'delete_transport',
    {
      description: 'Delete a transport booking from a trip.',
      inputSchema: {
        tripId: z.number().int().positive(),
        reservationId: z.number().int().positive(),
      },
      annotations: TOOL_ANNOTATIONS_DELETE,
    },
    async ({ tripId, reservationId }) => {
      if (isDemoUser(userId)) return demoDenied();
      if (!canAccessTrip(tripId, userId)) return noAccess();
      const { deleted } = deleteReservation(reservationId, tripId);
      if (!deleted) return { content: [{ type: 'text' as const, text: 'Transport not found.' }], isError: true };
      safeBroadcast(tripId, 'reservation:deleted', { reservationId });
      return ok({ success: true });
    }
  );
}
