/**
 * Social Content OS API Routes
 *
 * CRUD operations for social-content-os sub-resources:
 *   strategies, entries, campaigns, templates, hashtags, creatives, exports
 *
 * Uses the ModuleData model with moduleId prefixes like
 * "social-strategy:{companyId}", "social-hashtag:{companyId}", etc.
 */

import express, { Request, Response } from 'express';
import { authenticate } from '../middleware/auth';
import { requirePermission } from '../middleware/permissions';
import { ModuleData } from '../models/ModuleData';

const router = express.Router();
router.use(authenticate);

// ─── Helpers ──────────────────────────────────────────────────────────────────

const SUB_RESOURCES = [
  'strategies',
  'entries',
  'campaigns',
  'templates',
  'hashtags',
  'creatives',
  'exports',
] as const;

type SubResource = (typeof SUB_RESOURCES)[number];

/** Map URL path segment to ModuleData moduleId prefix */
function moduleIdFor(sub: SubResource, companyId: string): string {
  // e.g. "social-strategy:companyId123"
  const prefix: Record<SubResource, string> = {
    strategies: 'social-strategy',
    entries: 'social-entry',
    campaigns: 'social-campaign',
    templates: 'social-template',
    hashtags: 'social-hashtag',
    creatives: 'social-creative',
    exports: 'social-export',
  };
  return `${prefix[sub]}:${companyId}`;
}

// Authorise: user must belong to the company or be admin
function authorizeCompany(req: Request, companyId: string): boolean {
  return req.user!.companyIds.includes(companyId) || req.user!.role === 'admin';
}

// ─── Generic CRUD factories ──────────────────────────────────────────────────

/** GET /:sub/:companyId — list all items for a company */
function createGetAllRoute(sub: SubResource) {
  router.get(`/${sub}/:companyId`, async (req: Request, res: Response) => {
    try {
      const { companyId } = req.params;
      if (!authorizeCompany(req, companyId)) {
        res.status(403).json({ success: false, error: 'Access denied', message: 'You do not have access to this company' });
        return;
      }
      const mid = moduleIdFor(sub, companyId);
      const doc = await ModuleData.findOne({ moduleId: mid });
      if (!doc) {
        res.json([]);
        return;
      }
      // data is expected to be an array of items
      const items = Array.isArray(doc.data) ? doc.data : doc.data?.items ?? [];
      res.json(items);
    } catch (error: any) {
      console.error(`[social-content-os] GET /${sub} error:`, error.message);
      if (!res.headersSent) {
        res.status(500).json({ success: false, error: 'Server Error', message: error instanceof Error ? error.message : 'An unknown error occurred' });
      }
    }
  });
}

/** GET /:sub/detail/:id — get a single item by id */
function createGetDetailRoute(sub: SubResource) {
  router.get(`/${sub}/detail/:id`, async (req: Request, res: Response) => {
    try {
      const { id } = req.params;
      // We need to find the item across all companies the user has access to.
      // Since ModuleData stores items as an array in `data`, we search through user's companies.
      const companies = req.user!.companyIds;

      for (const companyId of companies) {
        const mid = moduleIdFor(sub, companyId);
        const doc = await ModuleData.findOne({ moduleId: mid });
        if (!doc) continue;

        const items: any[] = Array.isArray(doc.data) ? doc.data : doc.data?.items ?? [];
        const item = items.find((i: any) => (i.id ?? i._id?.toString()) === id);
        if (item) {
          res.json(item);
          return;
        }
      }

      // Also allow admin to search without company restriction
      if (req.user!.role === 'admin') {
        const pattern = moduleIdFor(sub, '');
        const docs = await ModuleData.find({ moduleId: { $regex: `^${pattern}` } });
        for (const doc of docs) {
          const items: any[] = Array.isArray(doc.data) ? doc.data : doc.data?.items ?? [];
          const item = items.find((i: any) => (i.id ?? i._id?.toString()) === id);
          if (item) {
            res.json(item);
            return;
          }
        }
      }

      res.status(404).json({ success: false, error: 'Not Found', message: `${sub.slice(0, -1)} item not found` });
    } catch (error: any) {
      console.error(`[social-content-os] GET /${sub}/detail error:`, error.message);
      if (!res.headersSent) {
        res.status(500).json({ success: false, error: 'Server Error', message: error instanceof Error ? error.message : 'An unknown error occurred' });
      }
    }
  });
}

/** POST /:sub — create items (bulk set or add to array) */
function createPostRoute(sub: SubResource) {
  router.post(`/${sub}`, requirePermission('social-media-os', 'create'), async (req: Request, res: Response) => {
    try {
      const { companyId, data } = req.body;
      if (!companyId) {
        res.status(400).json({ success: false, error: 'Bad Request', message: 'companyId is required' });
        return;
      }
      if (!authorizeCompany(req, companyId)) {
        res.status(403).json({ success: false, error: 'Access denied', message: 'You do not have access to this company' });
        return;
      }

      const mid = moduleIdFor(sub, companyId);
      const doc = await ModuleData.findOneAndUpdate(
        { moduleId: mid },
        { $set: { moduleId: mid, companyId, data } },
        { upsert: true, new: true },
      );

      const items = Array.isArray(doc.data) ? doc.data : doc.data?.items ?? [];
      res.status(201).json(items);
    } catch (error: any) {
      console.error(`[social-content-os] POST /${sub} error:`, error.message);
      if (!res.headersSent) {
        res.status(500).json({ success: false, error: 'Server Error', message: error instanceof Error ? error.message : 'An unknown error occurred' });
      }
    }
  });
}

/** PUT /:sub/:id — update a single item within the array */
function createPutRoute(sub: SubResource) {
  router.put(`/${sub}/:id`, requirePermission('social-media-os', 'edit'), async (req: Request, res: Response) => {
    try {
      const { id } = req.params;
      const { companyId, data: updateData } = req.body;
      if (!companyId) {
        res.status(400).json({ success: false, error: 'Bad Request', message: 'companyId is required' });
        return;
      }
      if (!authorizeCompany(req, companyId)) {
        res.status(403).json({ success: false, error: 'Access denied', message: 'You do not have access to this company' });
        return;
      }

      const mid = moduleIdFor(sub, companyId);
      const doc = await ModuleData.findOne({ moduleId: mid });
      if (!doc) {
        res.status(404).json({ success: false, error: 'Not Found', message: `${sub.slice(0, -1)} collection not found` });
        return;
      }

      let items: any[] = Array.isArray(doc.data) ? doc.data : doc.data?.items ?? [];
      const idx = items.findIndex((i: any) => (i.id ?? i._id?.toString()) === id);
      if (idx === -1) {
        res.status(404).json({ success: false, error: 'Not Found', message: `${sub.slice(0, -1)} item not found` });
        return;
      }

      items[idx] = { ...items[idx], ...updateData, id: items[idx].id ?? id, updatedAt: new Date().toISOString() };
      doc.data = items;
      await doc.save();

      res.json(items[idx]);
    } catch (error: any) {
      console.error(`[social-content-os] PUT /${sub} error:`, error.message);
      if (!res.headersSent) {
        res.status(500).json({ success: false, error: 'Server Error', message: error instanceof Error ? error.message : 'An unknown error occurred' });
      }
    }
  });
}

/** DELETE /:sub/:id — delete a single item from the array */
function createDeleteRoute(sub: SubResource) {
  router.delete(`/${sub}/:id`, requirePermission('social-media-os', 'delete'), async (req: Request, res: Response) => {
    try {
      const { id } = req.params;
      const companyId = req.query.companyId as string;
      if (!companyId) {
        res.status(400).json({ success: false, error: 'Bad Request', message: 'companyId query parameter is required' });
        return;
      }
      if (!authorizeCompany(req, companyId)) {
        res.status(403).json({ success: false, error: 'Access denied', message: 'You do not have access to this company' });
        return;
      }

      const mid = moduleIdFor(sub, companyId);
      const doc = await ModuleData.findOne({ moduleId: mid });
      if (!doc) {
        res.status(404).json({ success: false, error: 'Not Found', message: `${sub.slice(0, -1)} collection not found` });
        return;
      }

      let items: any[] = Array.isArray(doc.data) ? doc.data : doc.data?.items ?? [];
      const idx = items.findIndex((i: any) => (i.id ?? i._id?.toString()) === id);
      if (idx === -1) {
        res.status(404).json({ success: false, error: 'Not Found', message: `${sub.slice(0, -1)} item not found` });
        return;
      }

      const [removed] = items.splice(idx, 1);
      doc.data = items;
      await doc.save();

      res.json(removed);
    } catch (error: any) {
      console.error(`[social-content-os] DELETE /${sub} error:`, error.message);
      if (!res.headersSent) {
        res.status(500).json({ success: false, error: 'Server Error', message: error instanceof Error ? error.message : 'An unknown error occurred' });
      }
    }
  });
}

// ─── Register all routes for each sub-resource ────────────────────────────────

for (const sub of SUB_RESOURCES) {
  createGetAllRoute(sub);
  createGetDetailRoute(sub);
  createPostRoute(sub);
  createPutRoute(sub);
  createDeleteRoute(sub);
}

export default router;