import { Controller, Delete, Get, Middleware, Post, Put } from '@overnightjs/core';
import { Request, Response } from 'express';
import { auth, AuthRequest } from '../middleware/auth';
import BlogPost from '../models/BlogPost';
import ManualContent from '../models/ManualContent';
import SupportFeedback from '../models/SupportFeedback';
import Testimonial from '../models/Testimonial';
import User from '../models/User';
import { containsBlobMediaHtml } from '../utils/mediaUrlGuard';

const DEFAULT_MANUAL_CONTENT = {
  title: 'Manual de Usuario',
  subtitle: 'Esta guia explica, paso a paso, como usar todo el sitio para operar la clinica de forma completa.',
  quickStart: [
    'Inicia sesion con tu correo y contrasena.',
    'Abre Dashboard para revisar alertas y resumen del dia.',
    'Registra o busca al paciente en Pacientes.',
    'Agenda la cita desde Citas y confirma fecha/hora.',
    'Completa nota clinica y receta despues de la consulta.',
    'Revisa la agenda y los pendientes clinicos antes de cerrar la jornada.',
  ],
  menuMap: [
    { name: 'Dashboard', purpose: 'Resumen general, actividad reciente y accesos rapidos.' },
    { name: 'Pacientes', purpose: 'Alta, edicion, busqueda y consulta de expedientes.' },
    { name: 'Doctores', purpose: 'Registro y administracion del personal medico.' },
    { name: 'Citas', purpose: 'Calendario, programacion y seguimiento de consultas.' },
    { name: 'Recetas', purpose: 'Creacion y control de prescripciones medicas.' },
    { name: 'Perfil / Ajustes', purpose: 'Datos de cuenta, preferencias y seguridad.' },
    { name: 'Soporte', purpose: 'Canales de ayuda y envio de reportes.' },
  ],
  sections: [
    {
      id: 'vision-general',
      icon: 'Home',
      title: '1. Vision general del sistema',
      description:
        'MedKlinix centraliza operaciones de clinica: pacientes, doctores, citas, registros clinicos y recetas en una sola plataforma.',
      steps: [
        'Usa el menu lateral para cambiar de modulo.',
        'Usa el buscador para localizar registros rapidamente.',
        'Mantente en Dashboard para monitorear tareas pendientes y actividad.',
      ],
    },
    {
      id: 'pacientes',
      icon: 'Users',
      title: '2. Gestion de pacientes (flujo completo)',
      description: 'Este es el flujo principal para operar el sistema durante atencion diaria.',
      steps: [
        'Ir a Pacientes y hacer clic en Nuevo paciente.',
        'Completar datos obligatorios: nombre, contacto, fecha de nacimiento e identificacion.',
        'Guardar y confirmar que el paciente aparezca en el listado.',
        'Abrir el perfil del paciente para agregar historial clinico y observaciones.',
        'Usar filtros o busqueda por nombre/telefono para consultas futuras.',
      ],
    },
    {
      id: 'doctores',
      icon: 'Stethoscope',
      title: '3. Gestion de doctores',
      description: 'Permite mantener el equipo actualizado para asignaciones correctas de citas.',
      steps: [
        'Ir a Doctores y registrar medico con especialidad y datos de contacto.',
        'Validar que el doctor este activo en el listado.',
        'Actualizar informacion cuando cambie horario, especialidad o estado.',
      ],
    },
    {
      id: 'citas',
      icon: 'CalendarClock',
      title: '4. Citas y agenda',
      description: 'Controla la operacion diaria y evita conflictos de horario.',
      steps: [
        'Entrar en Citas y seleccionar fecha/hora disponible.',
        'Asignar paciente y doctor correctos.',
        'Guardar cita y revisar que aparezca en calendario.',
        'Si hay cambios, reprogramar o cancelar desde la misma vista.',
        'Al finalizar consulta, marcar estado correspondiente para seguimiento.',
      ],
    },
    {
      id: 'clinico-recetas',
      icon: 'FileText',
      title: '5. Registros clinicos y recetas',
      description: 'Documentacion medica clara y trazable por paciente.',
      steps: [
        'Desde el perfil del paciente, crear registro clinico nuevo.',
        'Guardar diagnostico, evolucion y recomendaciones.',
        'Crear receta con indicaciones y dosis exactas.',
        'Verificar que receta quede asociada al paciente correcto.',
      ],
    },
    {
      id: 'seguridad',
      icon: 'ShieldCheck',
      title: '6. Seguridad y buenas practicas',
      description: 'Proteccion de datos clinicos y acceso responsable.',
      steps: [
        'No compartir usuarios ni contrasenas.',
        'Cerrar sesion al terminar o al usar equipos compartidos.',
        'Actualizar credenciales periodicamente.',
        'Revisar permisos del equipo solo con personal autorizado.',
      ],
    },
    {
      id: 'soporte',
      icon: 'HeartPulse',
      title: '7. Soporte y resolucion de problemas',
      description: 'Pasos recomendados antes de escalar incidentes.',
      steps: [
        'Refrescar pagina si una vista no carga correctamente.',
        'Cerrar sesion e iniciar sesion otra vez si hay errores de acceso.',
        'Verificar conexion a internet y volver a intentar.',
        'Si persiste, abrir Soporte y enviar detalle del problema con modulo afectado.',
      ],
    },
  ],
  faq: [
    {
      q: 'No encuentro un paciente en busqueda.',
      a: 'Confirma ortografia, telefono o identificacion. Si no existe, registralo como nuevo paciente.',
    },
    {
      q: 'Una cita no aparece en calendario.',
      a: 'Revisa fecha, hora y estado de la cita. Refresca la pagina y valida filtros activos.',
    },
    {
      q: 'No puedo guardar una receta.',
      a: 'Verifica que el paciente este seleccionado y que los campos obligatorios esten completos.',
    },
  ],
};

@Controller('api/content')
export class ContentController {
  @Get('manual')
  async getManualContent(req: Request, res: Response) {
    try {
      const manual = await ManualContent.findOne({}).sort({ updatedAt: -1 }).lean();
      res.status(200).json({ success: true, data: manual || DEFAULT_MANUAL_CONTENT });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Get('manual/admin')
  @Middleware(auth)
  async getManualContentForAdmin(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }

      const manual = await ManualContent.findOne({}).sort({ updatedAt: -1 }).lean();
      res.status(200).json({ success: true, data: manual || DEFAULT_MANUAL_CONTENT });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Put('manual/admin')
  @Middleware(auth)
  async updateManualContent(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }

      const userId = authReq.user?.userId;
      if (!userId) {
        res.status(401).json({ success: false, error: 'Unauthorized' });
        return;
      }

      const { title, subtitle, quickStart, menuMap, sections, faq } = req.body as {
        title?: string;
        subtitle?: string;
        quickStart?: unknown;
        menuMap?: unknown;
        sections?: unknown;
        faq?: unknown;
      };

      if (!title?.trim() || !subtitle?.trim()) {
        res.status(400).json({ success: false, error: 'title and subtitle are required' });
        return;
      }
      if (!Array.isArray(quickStart) || !Array.isArray(menuMap) || !Array.isArray(sections) || !Array.isArray(faq)) {
        res.status(400).json({ success: false, error: 'quickStart, menuMap, sections, and faq must be arrays' });
        return;
      }

      const updated = await ManualContent.findOneAndUpdate(
        {},
        {
          $set: {
            title: title.trim(),
            subtitle: subtitle.trim(),
            quickStart,
            menuMap,
            sections,
            faq,
            updatedBy: userId,
          },
        },
        { new: true, upsert: true, setDefaultsOnInsert: true }
      ).lean();

      res.status(200).json({ success: true, data: updated });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Post('support-feedback')
  async createSupportFeedback(req: Request, res: Response) {
    try {
      const { name, email, subject, rating, message } = req.body as {
        name?: string;
        email?: string;
        subject?: string;
        rating?: number;
        message?: string;
      };

      if (!name || !email || !subject || !message) {
        res.status(400).json({ success: false, error: 'name, email, subject, and message are required' });
        return;
      }
      const normalizedRating = typeof rating === 'number' ? Math.round(rating) : 0;
      if (normalizedRating < 1 || normalizedRating > 5) {
        res.status(400).json({ success: false, error: 'rating must be between 1 and 5' });
        return;
      }

      const feedback = await SupportFeedback.create({
        name: name.trim(),
        email: email.trim().toLowerCase(),
        subject: subject.trim(),
        rating: normalizedRating,
        message: message.trim(),
      });

      res.status(201).json({ success: true, data: feedback });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Get('support-feedback/admin')
  @Middleware(auth)
  async getSupportFeedbackForAdmin(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }
      const feedback = await SupportFeedback.find({}).sort({ createdAt: -1 }).lean();
      res.status(200).json({ success: true, data: feedback });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Get('blogs')
  async getBlogs(req: Request, res: Response) {
    try {
      const limitParam = req.query.limit ? parseInt(req.query.limit as string, 10) : 0;
      const query = BlogPost.find({ published: true }).sort({ createdAt: -1 });
      if (limitParam > 0) {
        query.limit(limitParam);
      }
      const blogs = await query.lean();
      res.status(200).json({ success: true, data: blogs });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Get('blogs/admin')
  @Middleware(auth)
  async getBlogsForAdmin(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }
      const blogs = await BlogPost.find({}).sort({ createdAt: -1 }).lean();
      res.status(200).json({ success: true, data: blogs });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Post('blogs')
  @Middleware(auth)
  async createBlog(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }

      const { title, excerpt, content, published = true } = req.body as {
        title?: string;
        excerpt?: string;
        content?: string;
        published?: boolean;
      };

      if (!title || !excerpt || !content) {
        res.status(400).json({ success: false, error: 'title, excerpt, and content are required' });
        return;
      }

      if (containsBlobMediaHtml(content)) {
        res.status(400).json({ success: false, error: 'Blob media URLs are not supported. Use permanent file URLs.' });
        return;
      }

      const userId = authReq.user?.userId;
      if (!userId) {
        res.status(401).json({ success: false, error: 'Unauthorized' });
        return;
      }

      const user = await User.findById(userId).lean();
      const authorName = user ? `${user.firstName} ${user.lastName}`.trim() : 'Admin';

      const blog = await BlogPost.create({
        title: title.trim(),
        excerpt: excerpt.trim(),
        content: content.trim(),
        authorName,
        createdBy: userId,
        published,
      });

      res.status(201).json({ success: true, data: blog });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Put('blogs/:id')
  @Middleware(auth)
  async updateBlog(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }

      const { id } = req.params;
      const { title, excerpt, content, published } = req.body as {
        title?: string;
        excerpt?: string;
        content?: string;
        published?: boolean;
      };

      const updates: Record<string, unknown> = {};

      if (title !== undefined) {
        if (!title.trim()) {
          res.status(400).json({ success: false, error: 'title cannot be empty' });
          return;
        }
        updates.title = title.trim();
      }

      if (excerpt !== undefined) {
        if (!excerpt.trim()) {
          res.status(400).json({ success: false, error: 'excerpt cannot be empty' });
          return;
        }
        updates.excerpt = excerpt.trim();
      }

      if (content !== undefined) {
        if (!content.trim()) {
          res.status(400).json({ success: false, error: 'content cannot be empty' });
          return;
        }
        if (containsBlobMediaHtml(content)) {
          res.status(400).json({ success: false, error: 'Blob media URLs are not supported. Use permanent file URLs.' });
          return;
        }
        updates.content = content.trim();
      }

      if (typeof published === 'boolean') {
        updates.published = published;
      }

      if (Object.keys(updates).length === 0) {
        res.status(400).json({ success: false, error: 'No valid fields provided for update' });
        return;
      }

      const blog = await BlogPost.findByIdAndUpdate(id, updates, { new: true }).lean();
      if (!blog) {
        res.status(404).json({ success: false, error: 'Blog not found' });
        return;
      }

      res.status(200).json({ success: true, data: blog });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Put('blogs/:id/visibility')
  @Middleware(auth)
  async updateBlogVisibility(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }
      const { id } = req.params;
      const { published } = req.body as { published?: boolean };
      if (typeof published !== 'boolean') {
        res.status(400).json({ success: false, error: 'published boolean is required' });
        return;
      }
      const blog = await BlogPost.findByIdAndUpdate(id, { published }, { new: true });
      if (!blog) {
        res.status(404).json({ success: false, error: 'Blog not found' });
        return;
      }
      res.status(200).json({ success: true, data: blog });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Delete('blogs/:id')
  @Middleware(auth)
  async deleteBlog(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }
      const { id } = req.params;
      const deleted = await BlogPost.findByIdAndDelete(id).lean();
      if (!deleted) {
        res.status(404).json({ success: false, error: 'Blog not found' });
        return;
      }
      res.status(200).json({ success: true, data: deleted });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Get('testimonials')
  async getTestimonials(req: Request, res: Response) {
    try {
      const limitParam = req.query.limit ? parseInt(req.query.limit as string, 10) : 0;
      const query = Testimonial.find({ approved: true }).sort({ createdAt: -1 });
      if (limitParam > 0) {
        query.limit(limitParam);
      }
      const testimonials = await query.lean();
      res.status(200).json({ success: true, data: testimonials });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Get('testimonials/admin')
  @Middleware(auth)
  async getTestimonialsForAdmin(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }
      const testimonials = await Testimonial.find({}).sort({ createdAt: -1 }).lean();
      res.status(200).json({ success: true, data: testimonials });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Get('testimonials/mine')
  @Middleware(auth)
  async getMyTestimonials(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      const userId = authReq.user?.userId;
      if (!userId) {
        res.status(401).json({ success: false, error: 'Unauthorized' });
        return;
      }
      const myTestimonials = await Testimonial.find({ doctorId: userId })
        .sort({ createdAt: -1 })
        .lean();
      res.status(200).json({ success: true, data: myTestimonials });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Post('testimonials')
  @Middleware(auth)
  async createTestimonial(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      const userId = authReq.user?.userId;
      const role = authReq.user?.role;
      if (!userId) {
        res.status(401).json({ success: false, error: 'Unauthorized' });
        return;
      }
      if (role !== 'doctor' && role !== 'dentist') {
        res.status(403).json({ success: false, error: 'Only doctors can submit testimonials' });
        return;
      }

      const { quote, rating } = req.body as { quote?: string; rating?: number };
      if (!quote || quote.trim().length < 10) {
        res.status(400).json({ success: false, error: 'quote must be at least 10 characters' });
        return;
      }
      const normalizedRating = typeof rating === 'number' ? Math.round(rating) : 5;
      if (normalizedRating < 1 || normalizedRating > 5) {
        res.status(400).json({ success: false, error: 'rating must be between 1 and 5' });
        return;
      }

      const user = await User.findById(userId).lean();
      if (!user) {
        res.status(404).json({ success: false, error: 'User not found' });
        return;
      }

      const testimonial = await Testimonial.create({
        quote: quote.trim(),
        rating: normalizedRating,
        authorName: `${user.firstName} ${user.lastName}`.trim(),
        role: role === 'dentist' ? 'Dentist' : 'Doctor',
        doctorId: userId,
        approved: true,
      });

      res.status(201).json({ success: true, data: testimonial });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Put('testimonials/:id/visibility')
  @Middleware(auth)
  async updateTestimonialVisibility(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }
      const { id } = req.params;
      const { approved } = req.body as { approved?: boolean };
      if (typeof approved !== 'boolean') {
        res.status(400).json({ success: false, error: 'approved boolean is required' });
        return;
      }
      const updated = await Testimonial.findByIdAndUpdate(id, { approved }, { new: true }).lean();
      if (!updated) {
        res.status(404).json({ success: false, error: 'Testimonial not found' });
        return;
      }
      res.status(200).json({ success: true, data: updated });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }

  @Delete('testimonials/:id')
  @Middleware(auth)
  async deleteTestimonial(req: Request, res: Response) {
    try {
      const authReq = req as AuthRequest;
      if (authReq.user?.role !== 'admin') {
        res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
        return;
      }
      const { id } = req.params;
      const deleted = await Testimonial.findByIdAndDelete(id).lean();
      if (!deleted) {
        res.status(404).json({ success: false, error: 'Testimonial not found' });
        return;
      }
      res.status(200).json({ success: true, data: deleted });
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : 'Server error';
      res.status(500).json({ success: false, error: message });
    }
  }
}
