import { FastifyRequest, FastifyReply } from 'fastify';
import { CameraStatus } from '@prisma/client';

// Utility to generate slug from name
function slugify(text: string): string {
    return text
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, '_')
        .replace(/^_+|_+$/g, '');
}

// GET /api/cameras - List all cameras
export const getCameras = async (request: FastifyRequest, reply: FastifyReply) => {
    const cameras = await request.server.prisma.camera.findMany({
        orderBy: { name: 'asc' },
        include: {
            room: {
                select: {
                    id: true,
                    name: true,
                    code: true,
                    type: true
                }
            }
        }
    });
    return cameras;
};

// GET /api/cameras/:id - Get single camera
export const getCameraById = async (request: FastifyRequest, reply: FastifyReply) => {
    const { id } = request.params as { id: string };

    const camera = await request.server.prisma.camera.findUnique({
        where: { id },
        include: {
            room: {
                select: {
                    id: true,
                    name: true,
                    code: true,
                    type: true
                }
            }
        }
    });

    if (!camera) {
        return reply.status(404).send({ message: 'Camera not found' });
    }

    return camera;
};

// GET /api/cameras/:id/stream - Get stream URL for go2rtc
export const getCameraStream = async (request: FastifyRequest, reply: FastifyReply) => {
    const { id } = request.params as { id: string };

    const camera = await request.server.prisma.camera.findUnique({
        where: { id }
    });

    if (!camera) {
        return reply.status(404).send({ message: 'Camera not found' });
    }

    if (!camera.isActive) {
        return reply.status(503).send({ message: 'Camera is disabled' });
    }

    // Return go2rtc stream endpoints
    const go2rtcBase = process.env.GO2RTC_URL || 'http://go2rtc:1984';

    return {
        camera: {
            id: camera.id,
            name: camera.name,
            streamKey: camera.streamKey,
            status: camera.status
        },
        streams: {
            // go2rtc provides these endpoints automatically
            webrtc: `${go2rtcBase}/api/ws?src=${camera.streamKey}`,
            mse: `${go2rtcBase}/api/stream.mp4?src=${camera.streamKey}`,
            hls: `${go2rtcBase}/api/stream.m3u8?src=${camera.streamKey}`,
            snapshot: `${go2rtcBase}/api/frame.jpeg?src=${camera.streamKey}`
        }
    };
};

// POST /api/cameras - Create new camera
export const createCamera = async (request: FastifyRequest, reply: FastifyReply) => {
    const {
        name,
        streamKey,
        location,
        roomId,
        manufacturer,
        model,
        protocol,
        posX,
        posY,
        rotation,
        fov
    } = request.body as any;

    if (!name || !streamKey) {
        return reply.status(400).send({ message: 'Name and streamKey are required' });
    }

    const slug = slugify(name);

    // Check for duplicate slug
    const existing = await request.server.prisma.camera.findUnique({
        where: { slug }
    });

    if (existing) {
        return reply.status(409).send({ message: 'Camera with this name already exists' });
    }

    const camera = await request.server.prisma.camera.create({
        data: {
            name,
            slug,
            streamKey,
            location,
            roomId: roomId || null,
            manufacturer,
            model,
            protocol: protocol || 'RTSP',
            posX: posX ? parseInt(posX) : null,
            posY: posY ? parseInt(posY) : null,
            rotation: rotation ? parseInt(rotation) : 0,
            fov: fov ? parseInt(fov) : 90,
            status: CameraStatus.OFFLINE
        },
        include: {
            room: {
                select: {
                    id: true,
                    name: true,
                    code: true,
                    type: true
                }
            }
        }
    });

    return reply.status(201).send(camera);
};

// PUT /api/cameras/:id - Update camera
export const updateCamera = async (request: FastifyRequest, reply: FastifyReply) => {
    const { id } = request.params as { id: string };
    const {
        name,
        streamKey,
        location,
        roomId,
        manufacturer,
        model,
        protocol,
        isActive,
        posX,
        posY,
        rotation,
        fov
    } = request.body as any;

    const existing = await request.server.prisma.camera.findUnique({
        where: { id }
    });

    if (!existing) {
        return reply.status(404).send({ message: 'Camera not found' });
    }

    const data: any = {};

    if (name !== undefined) {
        data.name = name;
        data.slug = slugify(name);
    }
    if (streamKey !== undefined) data.streamKey = streamKey;
    if (location !== undefined) data.location = location;
    if (roomId !== undefined) data.roomId = roomId || null;
    if (manufacturer !== undefined) data.manufacturer = manufacturer;
    if (model !== undefined) data.model = model;
    if (protocol !== undefined) data.protocol = protocol;
    if (isActive !== undefined) data.isActive = isActive;
    if (posX !== undefined) data.posX = parseInt(posX);
    if (posY !== undefined) data.posY = parseInt(posY);
    if (rotation !== undefined) data.rotation = parseInt(rotation);
    if (fov !== undefined) data.fov = parseInt(fov);

    const camera = await request.server.prisma.camera.update({
        where: { id },
        data,
        include: {
            room: {
                select: {
                    id: true,
                    name: true,
                    code: true,
                    type: true
                }
            }
        }
    });

    return camera;
};

// DELETE /api/cameras/:id - Delete camera
export const deleteCamera = async (request: FastifyRequest, reply: FastifyReply) => {
    const { id } = request.params as { id: string };

    const existing = await request.server.prisma.camera.findUnique({
        where: { id }
    });

    if (!existing) {
        return reply.status(404).send({ message: 'Camera not found' });
    }

    await request.server.prisma.camera.delete({
        where: { id }
    });

    return reply.status(204).send();
};

// PATCH /api/cameras/:id/status - Update camera status (called by system/integrations)
export const updateCameraStatus = async (request: FastifyRequest, reply: FastifyReply) => {
    const { id } = request.params as { id: string };
    const { status } = request.body as { status: CameraStatus };

    if (!status || !Object.values(CameraStatus).includes(status)) {
        return reply.status(400).send({
            message: 'Invalid status. Must be one of: ONLINE, OFFLINE, IDLE, STREAMING, ERROR'
        });
    }

    const camera = await request.server.prisma.camera.update({
        where: { id },
        data: {
            status,
            lastSeen: new Date()
        }
    });

    return camera;
};
