import { Request, Response } from 'express';
import fs from 'fs';
import path from 'path';
import mongoose from 'mongoose';
import WarrantyTicket from '../models/WarrantyTicket';
import { IntegrationIdempotency } from '../models/IntegrationIdempotency';

const transitions = [
  { from: ['received'], to: 'warranty-check', action: 'start-warranty-check' },
  { from: ['warranty-check'], to: 'diagnosed', action: 'diagnose', requiredFields: ['diagnosis'] },
  { from: ['warranty-check'], to: 'closed', action: 'reject-not-covered', requiredFields: ['rejectionReason'] },
  { from: ['diagnosed'], to: 'submitted-to-manufacturer', action: 'submit-to-manufacturer', requiredFields: ['rmaCode', 'manufacturerName'] },
  { from: ['diagnosed'], to: 'repaired', action: 'repair-in-house', requiredFields: ['repairNotes'] },
  { from: ['submitted-to-manufacturer'], to: 'waiting-manufacturer', action: 'await-manufacturer' },
  { from: ['waiting-manufacturer'], to: 'replacement-ready', action: 'replacement-received', requiredFields: ['replacementSerial'] },
  { from: ['waiting-manufacturer'], to: 'repaired', action: 'repair-returned' },
  { from: ['replacement-ready', 'repaired'], to: 'closed', action: 'close-rma', requiredFields: ['closureNotes'] },
];

function byId(id: string): any {
  return mongoose.Types.ObjectId.isValid(id) ? { $or: [{ _id: id }, { id }] } : { id };
}
function output(doc: any): any {
  const value = doc?.toObject ? doc.toObject() : doc;
  if (value) value.id = value.id || String(value._id);
  return value;
}
function fail(res: Response, error: any, message: string): void {
  res.status(500).json({ success: false, message: error?.message || message });
}
function idempotencyKey(req: Request): string {
  return String(req.headers['idempotency-key'] || req.body?.idempotencyKey || '').trim();
}
async function replay(req: Request, res: Response): Promise<boolean> {
  const key = idempotencyKey(req);
  if (!key) return false;
  const stored = await IntegrationIdempotency.findOne({ key }).lean();
  if (!stored) return false;
  if (stored.method !== req.method || stored.path !== req.originalUrl) {
    res.status(409).json({ success: false, message: 'Idempotency key was already used for another request' });
    return true;
  }
  res.setHeader('X-Idempotent-Replay', 'true');
  res.status(stored.statusCode).json(stored.responsePayload);
  return true;
}
async function respond(req: Request, res: Response, statusCode: number, payload: any, resourceId?: string): Promise<void> {
  const key = idempotencyKey(req);
  if (key) {
    await IntegrationIdempotency.updateOne({ key }, { $setOnInsert: { key, method: req.method, path: req.originalUrl, statusCode, responsePayload: payload, resourceType: 'warranty', resourceId } }, { upsert: true }).catch(() => undefined);
  }
  res.status(statusCode).json(payload);
}

export async function listWarranty(req: Request, res: Response): Promise<void> {
  try {
    const filter: any = {};
    if (req.query.projectId) filter.projectId = String(req.query.projectId);
    if (req.query.status) filter.status = String(req.query.status);
    const docs = await WarrantyTicket.find(filter).sort({ updatedAt: -1 }).limit(Math.min(Number(req.query.limit) || 200, 500)).lean();
    res.json({ success: true, data: docs.map(output) });
  } catch (error) { fail(res, error, 'Failed to fetch warranty tickets'); }
}
export async function getWarranty(req: Request, res: Response): Promise<void> {
  try {
    const doc = await WarrantyTicket.findOne(byId(req.params.id));
    if (!doc) { res.status(404).json({ success: false, message: 'Warranty ticket not found' }); return; }
    res.json({ success: true, data: output(doc) });
  } catch (error) { fail(res, error, 'Failed to fetch warranty ticket'); }
}
export async function createWarranty(req: Request, res: Response): Promise<void> {
  try {
    if (await replay(req, res)) return;
    const body = { ...(req.body || {}), id: req.body?.id || `WBH-${Date.now()}-${Math.random().toString(36).slice(2, 6)}` };
    delete body._id;
    const doc = await WarrantyTicket.create(body);
    await respond(req, res, 201, { success: true, data: output(doc) }, String(doc._id));
  } catch (error) { fail(res, error, 'Failed to create warranty ticket'); }
}
export async function updateWarranty(req: Request, res: Response): Promise<void> {
  try {
    if (await replay(req, res)) return;
    const body = { ...(req.body || {}) };
    delete body._id; delete body.id; delete body.createdAt; delete body.updatedAt;
    const doc = await WarrantyTicket.findOneAndUpdate(byId(req.params.id), { $set: body }, { new: true, runValidators: true });
    if (!doc) { res.status(404).json({ success: false, message: 'Warranty ticket not found' }); return; }
    await respond(req, res, 200, { success: true, data: output(doc) }, String(doc._id));
  } catch (error) { fail(res, error, 'Failed to update warranty ticket'); }
}
export async function deleteWarranty(req: Request, res: Response): Promise<void> {
  try {
    if (await replay(req, res)) return;
    const doc = await WarrantyTicket.findOneAndDelete(byId(req.params.id));
    if (!doc) { res.status(404).json({ success: false, message: 'Warranty ticket not found' }); return; }
    await respond(req, res, 200, { success: true, data: output(doc) }, String(doc._id));
  } catch (error) { fail(res, error, 'Failed to delete warranty ticket'); }
}
export async function getRmaTransitions(req: Request, res: Response): Promise<void> {
  try {
    const doc: any = await WarrantyTicket.findOne(byId(req.params.id));
    if (!doc) { res.status(404).json({ success: false, message: 'Warranty ticket not found' }); return; }
    const status = doc.rmaStatus || 'received';
    res.json({ success: true, data: { rmaStatus: status, transitions: transitions.filter(item => item.from.includes(status)) } });
  } catch (error) { fail(res, error, 'Failed to fetch RMA transitions'); }
}
export async function transitionRma(req: Request, res: Response): Promise<void> {
  try {
    const doc: any = await WarrantyTicket.findOne(byId(req.params.id));
    if (!doc) { res.status(404).json({ success: false, message: 'Warranty ticket not found' }); return; }
    const body = req.body || {};
    const current = doc.rmaStatus || 'received';
    const transition = transitions.find(item => item.action === body.action && item.from.includes(current));
    if (!transition) { res.status(400).json({ success: false, message: `Invalid transition from ${current}` }); return; }
    const missing = (transition.requiredFields || []).filter(field => !String(body[field] || '').trim());
    if (missing.length) { res.status(400).json({ success: false, message: `Missing required fields: ${missing.join(', ')}` }); return; }
    ['rmaCode', 'manufacturerName', 'diagnosis', 'repairNotes', 'rejectionReason', 'replacementSerial', 'closureNotes'].forEach(field => {
      if (body[field] !== undefined) doc[field] = body[field];
    });
    doc.rmaStatus = transition.to;
    doc.rmaHistory.push({ status: transition.to, action: body.action, note: body.note || '', userId: body.userId, userName: body.userName, timestamp: new Date() });
    await doc.save();
    res.json({ success: true, data: { ticket: output(doc), transition } });
  } catch (error) { fail(res, error, 'Failed to apply RMA transition'); }
}
export async function appendWarrantyItem(req: Request, res: Response): Promise<void> {
  try {
    const fields: any = { attachments: 'attachments', assets: 'assets', 'work-orders': 'workOrders' };
    const field = fields[req.params.kind];
    if (!field) { res.status(400).json({ success: false, message: 'Invalid collection' }); return; }
    const item = { ...(req.body || {}), id: req.body?.id || Date.now().toString() };
    const doc = await WarrantyTicket.findOneAndUpdate(byId(req.params.id), { $push: { [field]: item } }, { new: true });
    if (!doc) { res.status(404).json({ success: false, message: 'Warranty ticket not found' }); return; }
    res.status(201).json({ success: true, data: output(doc) });
  } catch (error) { fail(res, error, 'Failed to append warranty item'); }
}
export async function uploadWarrantyFiles(req: Request, res: Response): Promise<void> {
  try {
    const doc: any = await WarrantyTicket.findOne(byId(req.params.id));
    if (!doc) { res.status(404).json({ success: false, message: 'Warranty ticket not found' }); return; }
    const field = req.params.kind === 'field-images' ? 'fieldImages' : 'attachments';
    const folder = field === 'fieldImages' ? 'warranty-field-images' : 'warranty-docs';
    const files = Array.isArray(req.body?.files) ? req.body.files : [req.body];
    if (!files.length || files.some((file: any) => !file?.contentBase64)) { res.status(400).json({ success: false, message: 'Missing file content' }); return; }
    const directory = path.join(process.cwd(), 'uploads', folder);
    fs.mkdirSync(directory, { recursive: true });
    const saved = files.map((file: any) => {
      const original = String(file.fileName || 'file.bin');
      const ext = path.extname(original).replace(/[^a-zA-Z0-9.]/g, '') || '.bin';
      const filename = `warranty-${Date.now()}-${Math.round(Math.random() * 1e9)}${ext}`;
      fs.writeFileSync(path.join(directory, filename), Buffer.from(String(file.contentBase64), 'base64'));
      return { name: original, filename, url: `/uploads/${folder}/${filename}`, uploadedAt: new Date() };
    });
    doc[field].push(...saved);
    await doc.save();
    res.status(201).json({ success: true, data: { files: saved, ticket: output(doc) } });
  } catch (error) { fail(res, error, 'Failed to upload warranty files'); }
}