const express = require('express');
const app = express();
const path = require('path');
const http = require('http').createServer(app);
const cors = require('cors');
const moment = require('moment-jalaali');
const MessageModel = require('./models/MessageModel');
const fs = require('fs-extra');
const cron = require('node-cron');
const UserModel = require('./models/UserModel');
const blockCheck = require('./middlewares/blockCheck');
const rateLimit = require('express-rate-limit');
const { default: axios } = require('axios');

const allowedOrigins = [
  'http://localhost:3000',
  'http://localhost:3001',  // اضافه شد — مهم برای توسعه فرانت
  'http://localhost:3002',
  'http://localhost:3003',
  'http://localhost',
  'https://modstagram.com',
  'https://www.modstagram.com',
  'https://api.modstagram.com',
  'https://panel.modstagram.com',
  'https://www.panel.modstagram.com',
  'https://panel.modstagram.ir',
  'https://www.panel.modstagram.ir',
  'ionic://localhost',
  'capacitor://localhost',
  // IPهای محلی (برای تست در شبکه داخلی)
  /^http:\/\/192\.168\.\d{1,3}\.\d{1,3}:\d+$/,
  /^http:\/\/10\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$/,
];

app.use(cors({
  origin: (origin, callback) => {
    // در محیط توسعه، همه originها مجاز باشن
    if (process.env.NODE_ENV !== 'production') {
      return callback(null, true);
    }

    // اگر origin وجود نداشته باشه (مثل درخواست از موبایل یا Postman) اجازه بده
    if (!origin) {
      return callback(null, true);
    }

    // چک لیست یا RegExp
    const isAllowed = allowedOrigins.some(item => {
      if (typeof item === 'string') return item === origin;
      if (item instanceof RegExp) return item.test(origin);
      return false;
    });

    if (isAllowed) {
      callback(null, true);
    } else {
      callback(new Error('Not allowed by CORS'));
    }
  },
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'x-no-toast'],
  credentials: true,
  optionsSuccessStatus: 200 // برای مرورگرهای قدیمی
}));

// Socket.IO CORS
const io = require('socket.io')(http, {
  cors: {
    origin: (origin, callback) => {
      if (process.env.NODE_ENV !== 'production') {
        return callback(null, true);
      }

      if (!origin) {
        return callback(null, true);
      }

      const isAllowed = allowedOrigins.some(item => {
        if (typeof item === 'string') return item === origin;
        if (item instanceof RegExp) return item.test(origin);
        return false;
      });

      if (isAllowed) {
        callback(null, true);
      } else {
        callback(new Error('Not allowed by CORS'));
      }
    },
    methods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS'],
    credentials: true
  }
});

// افزایش limit برای Base64 (1000mb کافیه)
app.use(express.json({ limit: '1000mb' }));
app.use(express.urlencoded({ limit: '1000mb', extended: true }));

app.use('/storage', express.static(path.join(__dirname, 'storage')));
app.use('/storage/profiles', express.static(path.join(__dirname, '../storage/profiles')));
app.use('/storage/carts', express.static(path.join(__dirname, '../storage/carts')));
app.use('/storage/posts', express.static(path.join(__dirname, '../storage/posts')));
app.use('/storage/messages', express.static(path.join(__dirname, '../storage/messages')));
app.use('/storage/tickets', express.static(path.join(__dirname, '../storage/tickets')));
app.use('/storage/advertising', express.static(path.join(__dirname, '../storage/advertising')));
app.use('/storage/services', express.static(path.join(__dirname, '../storage/services')));

require('./boot');

// غیرفعال کردن پارس‌کننده‌های بدنه برای روت‌های آپلود فایل
app.use((req, res, next) => {
  if (req.path === '/api/v1/posts/create' && req.method === 'POST') {
    console.log('DEBUG: Skipping body parsers for /api/v1/posts/create');
    return next();
  }
  express.json()(req, res, next);
});
app.use((req, res, next) => {
  if (req.path === '/api/v1/posts/create' && req.method === 'POST') {
    return next();
  }
  express.urlencoded({ extended: true })(req, res, next);
});

require('./middlewares')(app);

const limiter = rateLimit({
  windowMs: 3 * 60 * 1000,
  max: 3000,
  standardHeaders: true,
  legacyHeaders: false,
  message: 'تعداد درخواست‌های شما بیشتر از حد مجاز است، لطفاً بعداً دوباره تلاش کنید.',
  handler: (req, res) => {
    const retryAfter = Math.ceil((req.rateLimit.resetTime - Date.now()) / 1000);
    res.set('Retry-After', retryAfter);
    res.status(429).json({
      error: `شما بیش از حد مجاز درخواست ارسال کرده‌اید. لطفاً بعد از ${retryAfter} ثانیه دوباره تلاش کنید.`
    });
  }
});
app.use(limiter);
app.set('trust proxy', 'loopback');

require('./routes')(app);

const { enrichMessage, emitChatEvents, parseForwardedContent } = require('./helpers/chatHelpers')

app.get('/api/v1/chat', async (req, res) => {
  try {
    const { senderId, receiverId, limit, page } = req.query
    const pageNumber = parseInt(page) || 1
    const limitPerPage = parseInt(limit) || 40

    const filter = {
      $or: [
        { senderId, receiverId },
        { senderId: receiverId, receiverId: senderId }
      ]
    }

    const totalMessagesCount = await MessageModel.countDocuments(filter)
    const totalPages = Math.ceil(totalMessagesCount / limitPerPage) || 1
    const skip = (pageNumber - 1) * limitPerPage

    const messages = await MessageModel.find(filter)
      .sort({ createdAt: -1 })
      .skip(skip)
      .limit(limitPerPage)

    await MessageModel.updateMany(
      { _id: { $in: messages.map((m) => m._id) }, receiverId: senderId },
      { $set: { readStatus: 1 } }
    )

    const enriched = await Promise.all(messages.map((m) => enrichMessage(m)))
    res.json({ messages: enriched.reverse(), totalPages })
  } catch (error) {
    console.error('Error fetching messages:', error)
    res.status(500).json({ error: 'Server error' })
  }
})

app.post('/api/v1/chat', [blockCheck], async (req, res) => {
  try {
    const { senderId, receiverId, content, replyToId, forwardedFrom: fwdBody } = req.body
    const { body, forwardedFrom: fwdParsed } = parseForwardedContent(content)

    const payload = {
      senderId,
      receiverId,
      content: body || content,
      replyToId: replyToId || undefined,
      forwardedFrom: fwdBody || fwdParsed || undefined
    }

    const newMessage = new MessageModel(payload)
    await newMessage.save()
    const formatted = await enrichMessage(newMessage)

    res.status(201).json({ data: formatted })
    emitChatEvents(io, formatted, senderId, receiverId)
  } catch (error) {
    console.error('Error sending message:', error)
    res.status(500).json({ error: 'Server error' })
  }
})
app.get('/api/v1/chat/read', async (req, res) => {
  try {
    const { senderId, receiverId } = req.query // شناسه فرستنده و گیرنده از درخواست دریافت شود
    // پیدا کردن تمام پیام‌هایی که کاربر دوم مشاهده کرده است و کاربر اول آنها را ارسال کرده است
    const messages = await MessageModel.find(
      { senderId: receiverId, receiverId: senderId } // برای مواقعی که شناسه‌ها معکوس باشند
    )
    // به روزرسانی وضعیت خوانده شده یا نشده بودن پیام‌ها به "خوانده شده"
    await MessageModel.updateMany({ _id: { $in: messages.map(message => message._id) } }, { $set: { readStatus: 1 } })
    res.status(200).json({ message: 'Message read status updated successfully' })
  } catch (error) {
    console.error('Error updating message read status:', error)
    res.status(500).json({ error: 'Server error' })
  }
})

app.post("/api/v1/notification/send-sms", async (req, res) => {
  const { receiverId, message } = req.body;
  const user = await UserModel.findById(receiverId);
  if (!user || !user.mobile) return res.status(404).json({ error: "User not found" });
  console.log("3");
  
  const mobile =  user.mobile
  const user_name =  user.user_name
  const data = JSON.stringify({
    mobile,
    templateId: '876533',
    parameters: [
      { name: 'USER', value: user_name }
    ]
  })

  const config = {
    method: 'post',
    url: 'https://api.sms.ir/v1/send/verify',
    headers: {
      'Content-Type': 'application/json',
      Accept: 'text/plain',
      'x-api-key': '2JKxGbTzE64t0YTkjip6RYHnm9mq1haMlidF8WWwQunwubHFVW6iaMmfFQbMXEDt'
    },
    data
  }

  axios(config)
    .then(function (response) {
      console.log(response);
      
    })
    .catch(function (error) {
      console.log(error)
    })
 
  res.status(200).json({ success: true });
});

app.post('/api/v1/chat/file', [blockCheck], async (req, res) => {
  try {
    const { senderId, receiverId, content, replyToId, fileType } = req.body
    const { file } = req.files
    let fileUrl = null
    if (file) {
      const uploadDir = path.join(__dirname, '../storage/messages')
      if (!fs.existsSync(uploadDir)) {
        fs.mkdirSync(uploadDir, { recursive: true })
      }
      const uniqueFileName = `${Date.now()}-${file.name}`
      const filePath = path.join(uploadDir, uniqueFileName)
      await fs.move(file.path, filePath)
      fileUrl = `/messages/${uniqueFileName}`
    }

    const newMessage = new MessageModel({
      senderId,
      receiverId,
      content: content || '',
      file: fileUrl,
      fileType: fileType || undefined,
      replyToId: replyToId || undefined
    })
    await newMessage.save()
    const formatted = await enrichMessage(newMessage)

    res.status(201).json({ data: formatted })
    emitChatEvents(io, formatted, senderId, receiverId)
  } catch (error) {
    console.error('Error sending message:', error)
    res.status(500).json({ error: 'Server error' })
  }
})
// Errors
require('./middlewares/exception')(app)
require('./middlewares/404')(app)
io.on('connection', (socket) => {
  socket.on('joinUser', ({ userId }) => {
    if (userId) socket.join(`user:${userId}`)
  })

  socket.on('joinChat', ({ userId, receiverId }) => {
    if (userId && receiverId) {
      socket.join(`chat:${userId}:${receiverId}`)
      socket.join(`chat:${receiverId}:${userId}`)
    }
  })

  socket.on('typing', ({ senderId, receiverId }) => {
    io.to(`chat:${receiverId}:${senderId}`).emit('userTyping', { userId: senderId })
  })

  socket.on('stopTyping', ({ senderId, receiverId }) => {
    io.to(`chat:${receiverId}:${senderId}`).emit('userStoppedTyping', { userId: senderId })
  })

  socket.on('messageSeen', async ({ messageId, senderId, receiverId }) => {
    try {
      if (messageId) {
        await MessageModel.findByIdAndUpdate(messageId, { readStatus: 1 })
        io.to(`chat:${receiverId}:${senderId}`).emit('messageStatusUpdate', {
          messageId,
          status: 'seen'
        })
      }
    } catch (e) {
      console.error('messageSeen error', e)
    }
  })
})

// Free Project
require('./services/AdvertisingCron')
require('./services/ProjectCron')
cron.schedule('0 0 1 * *', async () => {
  try {
    await UserModel.updateMany({}, {
      daily_free_request: 1,
      last_free_request_date: new Date(),
      monthly_free_offer: 1,
      last_free_offer_date: new Date()
    })
    console.log('Monthly free requests reset for all users.')
  } catch (error) {
    console.error('Error resetting daily free requests:', error)
  }
}, {
  scheduled: true,
  timezone: 'Asia/Tehran'
})
module.exports = (port) => {
  http.listen(port, () => {
    console.log(`HTTP server is running on port ${port}`)
  })
}
