/**
 * Module dependencies.
 */
 'use strict';
 var childControllers = [];
 var async = require('async');
 var mv = require('mv');
 var fs = require('fs');
 var path = require('path');
 const archiver = require('archiver');
//var utils = rekuire('/lib/utils');
var extend = require('util')._extend;
var ObjectId = require('mongoose').Types.ObjectId
var viewsDir = 'app/views/'
module.exports.getChildControllers = function(){
	return childControllers;
};
module.exports.inherit = function (child) {
	/**
	 * Load
	 */
	 if(childControllers.indexInArray(child, function(item){return this.pluralName == item.pluralName}) == -1){
	 	childControllers.push(child);
	 };
	 child.super = {};
	 child.elements = []
	 child.coveredMethods = [];
	 child.coveredMethods.push("load");
	 child.load = function (req, res, next, id) {
	 	if(ObjectId.isValid(id)){
		 	child.model.load(id, function (err, model) {
		 		if (err){
		 			res.errors.push(err)
		 			res.statusData = "Error";
		 			return next(err);
		 		}
		 		if (!model){
		 			res.statusData = "Error"
		 			return next(new Error('not found'));
		 		}
		 		if (!model.canSeeByUser(req.user)) {
		 			//req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
		 			if(req.user){
		 				res.statusData = "Error"
		 				return res.redirect('/users/' + req.user.id);
		 			}else{
		 				res.statusData = "Error"
		 				return res.redirect('/login');
					}
		 			return;
		 		}
		 		req[child.singularName] = model;
		 		next();
		 	});
		 }else{
		 	next()
		 }
	 };


	/**
	 * List
	 */

	 child.coveredMethods.push("index");
	 child.index = function (req, res) {
		//if (!utils.canAccessByUser(req.user, child.pluralName, child.group)) {
		//	req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
		//	res.redirect('/users/' + req.user.id);
		//	return;
		//};


		var callback = function (err, models) {
			if (err) {
				res.statusData = "Error"
				return res.render('500', {});
			}
			child.model.count(options.criteria || {}).exec(function (err, count) {
				var pageCount = Math.ceil(count / perPage);
				var pages = [];
				var start =  pageCount > 10 && page - 5 > 0 ?  page - 5 : 0;
				var end =  pageCount > 10 && page + 5 < pageCount ? page + 5 : pageCount;
				for(var i = start; i < end; i++){
					pages.push(i);
				}
				if(start > 0){
					pages.splice(0,0, "...");
					pages.splice(0,0,0);
				}
				if(end < pageCount){
					pages.push("...");
					pages.push(pageCount - 1);
				}
				var data = {
					user: req.user,
					title: child.title + ' Listesi',
					page: page + 1,
					pages: pages,
					perPage: perPage,
					pageCount: pageCount,
					isFiltered: Object.keys(req.anyKey).length > 0 ? true : false,
					//menu: utils.getUserMenu(req.user),
				};
				data[child.pluralName] = models;
				data["items"] = models;
				data["pluralName"] = child.pluralName
				data["singularName"] = child.singularName
				data["title"] = child.title
				res.errors.push(err)
				child.loadRelatedData(data, req, res, function (relatedData) {
					data.inject(relatedData);
					res.statusData = "Success"

					if(fs.existsSync(viewsDir + child.pluralName)){
						res.render(child.pluralName + '/index', data);
					}else{
						res.render("__basicItems" + '/index', data);
					}
				});
			});
		}

		var page = parseInt(req.anyKey.page > 0 ? req.anyKey.page : 1) - 1;
		var perPage = parseInt(req.anyKey.perPage > 0 ? req.anyKey.perPage : 10);
		var text = req.anyKey.q
		var options = {
			perPage: perPage,
			page: page,
			search: text,
			criteria:{}
		};
		options.inject(req.options)

		if(child.model.generateCriteria){
			options.criteria.inject(child.model.generateCriteria(req.anyKey))
		}

		if(child.model.listByUserOptions){
			options.criteria = child.model.listByUserOptions(options, req.user, callback)
		}else{
			options.criteria = child.model.list(options, callback);
		}
	};

	/**
	 * New article
	 */

	 child.coveredMethods.push("new");
	 child.new = function (req, res) {
		//if (!utils.canAccessByUser(req.user, child.pluralName, child.group)) {
		//	req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
		//	res.redirect('/users/' + req.user.id);
		//	return;
		//};

		var data = {
			user: req.user,
			title: child.title,
			pluralName: child.pluralName,
			//menu: utils.getUserMenu(req.user),
		};
		var virtual = new child.model({});
		if (virtual){// && virtual.canEditByUser(req.user)) {
			child.loadRelatedData(data, req, res, function (relatedData) {
				data.inject(relatedData);
				res.statusData = "Success"


				if(fs.existsSync(viewsDir + child.pluralName)){
					res.render(child.pluralName + '/new', data);
				}else{
					res.render("__basicItems" + '/new', data);
				}
			});
		} else {
			req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
			if(req.user){
				res.statusData = "Error"
				return res.redirect('/users/' + req.user.id);
			}else{
				res.statusData = "Error"
				return res.redirect('/login');
			}

		}
	};

	/**
	 * Create an article
	 * Upload an image
	 */

	 child.coveredMethods.push("create");
	 child.create = function (req, res) {
		//if (!utils.canAccessByUser(req.user, child.pluralName, child.group)) {
		//	req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
		//	res.redirect('/users/' + req.user.id);
		//	return;
		//};
		var model = new child.model(req.body);
		model.user = req.user;
		if (model && model.canEditByUser(req.user)) {
			model.save(function (err) {
				req[child.singularName] = model
				child.handleFiles(req, res, function(error){
					if (!err && !error) {
						req.flash('success', child.title + ' Başarıyla Yaratıldı');
						res.model = model
						res.model[child.singularName] = model
						res.statusData = "Success"
						if(req.anyKey.__redirectUrl){
							return res.redirect(req.anyKey.__redirectUrl);
						}else{
							return res.redirect('/' + child.pluralName);
						}
					} else if (child.onError) {
						//console.log(err);
						res.statusData = "Error"
						child.onError(req, res, 'create', err ? err : error);
					} else if(req.user){
						//console.log(err);
						//console.log(err.stacktrace);
						req.flash('info', 'Bilinmeyen bir hata oluştu');
							if(err){
								res.errors.push(err)
								req.flash('error', err.message);
							}
							if(error){
								res.errors.push(error)
								req.flash('error', error.message);
							}
						res.statusData = "Error"
						res.redirect('/users/' + req.user.id);
					}else {
						req.flash('info', 'Bilinmeyen bir hata oluştu');
							if(err){
								res.errors.push(err)
								req.flash('error', err.message);
							}
							if(error){
								res.errors.push(error)
								req.flash('error', error.message);
							}
						res.statusData = "Error"
						res.redirect('/login/');
					}
				})
			});
		} else {
			//EWLog("yetki", child.singularName, req[child.singularName])
			req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
			if(req.user){
				res.statusData = "Error"
				return res.redirect('/users/' + req.user.id);
			}else{
				res.statusData = "Error"
				return res.redirect('/login');
			}
		}
	};

	/**
	 * Edit an article
	 */

	 child.coveredMethods.push("edit");
	 child.edit = function (req, res) {
		//if (!utils.canAccessByUser(req.user, child.pluralName, child.group)) {
		//	req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
		//	res.redirect('/users/' + req.user.id);
		//	return;
		//};
		var data = {
			user: req.user,
			title: child.title,
			pluralName: child.pluralName,
			//menu: utils.getUserMenu(req.user),
		};

		data[child.singularName] = req[child.singularName];
		if (data[child.singularName]){// && data[child.singularName].canEditByUser(req.user)) {
			child.loadRelatedData(data, req, res, function (relatedData) {
				data.inject(relatedData);
				res.statusData = "Success"
				data.item = data[child.singularName]
				if(fs.existsSync(viewsDir + child.pluralName)){
					res.render(child.pluralName + '/edit', data);
				}else{
					res.render("__basicItems" + '/edit', data);
				}
			});
		} else {
			req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
			if(req.user){
				res.statusData = "Error"
				return res.redirect('/users/' + req.user.id);
			}else{
				res.statusData = "Error"
				return res.redirect('/login');
			}
		}

	};

	/**
	 * Update article
	 */

	 child.coveredMethods.push("update");
	 child.update = function (req, res) {
		//if (!utils.canAccessByUser(req.user, child.pluralName, child.group)) {
		//	req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
		//	res.redirect('/users/' + req.user.id);
		//	return;
		//};
		var model = req[child.singularName];

		// make sure no one changes the user
		delete req.body.user;
		if (model){// && model.canEditByUser(req.user)) {
			model = extend(model, req.body);
			if (model && model.canEditByUser(req.user)) {
				child.handleFiles(req, res, function(err){
					model.save(function (error, model) {
						//EWLog(error, err)
						if (!err && !error) {
							req.flash('success', child.title + ' Başarıyla Güncellendi');
							res.model = model
							res.statusData = "Success"

							if(req.anyKey.__redirectUrl){
								return res.redirect(req.anyKey.__redirectUrl);
							}else{
								return res.redirect('/' + child.pluralName);
							}
						} else if (child.onError) {
							//	console.log(err);
							req.flash('info', 'Bilinmeyen bir hata oluştu');
							if(err){
								res.errors.push(err)
								req.flash('error', err.message);
							}
							if(error){
								res.errors.push(error)
								req.flash('error', error.message);
							}
							res.statusData = "Error"
							child.onError(req, res, 'update', err || error);
						} else {
							//	console.log(err.stacktrace);
							req.flash('info', 'Bilinmeyen bir hata oluştu');
							if(err){
								res.errors.push(err)
								req.flash('error', err.message);
							}
							if(error){
								res.errors.push(error)
								req.flash('error', error.message);
							}
							res.statusData = "Error"
							res.redirect('/users/' + req.user.id);
						}
					});
				})
			} else {
				req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
				if(req.user){
					res.statusData = "Error"
					return res.redirect('/users/' + req.user.id);
				}else{
					res.statusData = "Error"
					return res.redirect('/login');
				}
			}
		} else {
			req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
			if(req.user){
				res.statusData = "Error"
				return res.redirect('/users/' + req.user.id);
			}else{
				res.statusData = "Error"
				return res.redirect('/login');
			}
		}
	};

	/**
	 * Show
	 */
	 child.coveredMethods.push("show");
	 child.show = function (req, res) {
		//if (!utils.canAccessByUser(req.user, child.pluralName, child.group)) {
		//	req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
		//	res.redirect('/users/' + req.user.id);
		//	return;
		//};
		var data = {
			title: child.title,
			pluralName: child.pluralName,
			//menu: utils.getUserMenu(req.user),
		};
		data[child.singularName] = req[child.singularName];
		if (data[child.singularName] && data[child.singularName].canSeeByUser(req.user)) {
			child.loadRelatedData(data, req, res, function (relatedData) {
				data.inject(relatedData)
				res.statusData = "Success"
				data.item = data[child.singularName]
				if(fs.existsSync(viewsDir + child.pluralName)){
					res.render(child.pluralName + '/show', data);
				}else{
					res.render("__basicItems" + '/show', data);
				}
			})
		} else {
			req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
			if(req.user){
				res.statusData = "Error"
				return res.redirect('/users/' + req.user.id);
			}else{
				res.statusData = "Error"
				return res.redirect('/login');
			}
		}
	};

	/**
	 * Delete an company
	 */

	 child.coveredMethods.push("destroy");
	 child.destroy = function (req, res) {
		//if (!utils.canAccessByUser(req.user, child.pluralName, child.group)) {
		//	req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
		//	res.redirect('/users/' + req.user.id);
		//	return;
		//};
		var model = req[child.singularName];
		if (model && model.canEditByUser(req.user)) {
			model.remove(function (err) {
				req.flash('info', 'Başarıyla Silindi');
				res.statusData = "Success"

				if(req.anyKey.__redirectUrl){
					return res.redirect(req.anyKey.__redirectUrl);
				}else{
					return res.redirect('/' + child.pluralName);
				}
			});
		}else{
			req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
			if(req.user){
				res.statusData = "Error"
				return res.redirect('/users/' + req.user.id);
			}else{
				res.statusData = "Error"
				return res.redirect('/login');
			}
		}
	};


	 child.coveredMethods.push("destroyMultiple");
	 child.destroyMultiple = function (req, res) {

	 	var callback = function(){

	 	}
		var page = parseInt(req.anyKey.page > 0 ? req.anyKey.page : 1) - 1;
		var perPage = parseInt(req.anyKey.perPage > 0 ? req.anyKey.perPage : 10);
		var text = req.anyKey.q
		var options = {
			perPage: perPage,
			page: page,
			search: text

		};
		options.inject(req.options)

		var ids = req.anyKey.ids
		if(ids.indexOf("all") == -1){
			options["criteria"] = {_id: {$in: ids}}
		}
		var criteria = {}
		if(child.model.listByUserOptions){
			criteria = child.model.listByUserOptions(options, req.user, callback)
		}else{
			criteria = child.model.list(options, callback);
		}
		child.model.deleteMany(criteria, function(err){
			req.flash('info', 'Başarıyla Silindi');
			res.statusData = "Success"

			if(req.anyKey.__redirectUrl){
				return res.redirect(req.anyKey.__redirectUrl);
			}else{
				return res.redirect('/' + child.pluralName);
			}
		})
	}


	child.coveredMethods.push("loadRelatedData");
	child.loadRelatedData = function (data, req, res, callback) {
		data.extras = {
			pluralName : child.pluralName,
			singularName : child.singularName
		}
		data.elements = child.elements
		data.url = req.url,
		data.user = req.user
		if(req.csrfToken){
			data.csrf_token = req.csrfToken()
		}
		callback(data);
	};
	child.super.loadRelatedData = child.loadRelatedData
	child.coveredMethods.push("authFilter");
	child.authFilter = function (req, res, documents, callback) {
		callback(documents);
	}
	child.coveredMethods.push("search");
	child.search = function (req, res) {
		var text = req.body.text
		if (text) {
			child.model.find(
				{$text: {$search: text}},
				{score: {$meta: "textScore"}}
				)
			.sort({score: {$meta: "textScore"}})
			.limit(20)
			.exec(function (error, documents) {//this is standard  array.filter method;
					documents = documents.filter(function (doc) {
						return doc.canSeeByUser(req.user)
					});
					if (documents) {
						res.json({query: text, results: documents});
					} else {
						res.json({});
					}

			});
		}

	};
	child.coveredMethods.push("lookFile");
	child.lookFile = function(req, res){
			if(req[child.singularName] && req[child.singularName].canSeeByUser(req.user)){
				res.sendFile(path.resolve('uploads/' + child.singularName + "/" + req[child.singularName]['id'] + '/' + req.params.fileName))
			}else{
				res.json({error: "You are not authorized"})
			}
	}
  child.coveredMethods.push("lookMultipleFiles");
  child.lookMultipleFiles = function(req, res) {
    if (req[child.singularName] && req[child.singularName].canSeeByUser(req.user)) {
      const zipNames = req.params.zipName.split('&').map(name => name.trim());
      const id = req[child.singularName]._id.toString();
      const uploadPath = path.resolve('uploads', child.singularName, id.toString());
      const zipFileName = `${id}.zip`;
      const zipFilePath = path.join(uploadPath, zipFileName);
      const output = fs.createWriteStream(zipFilePath);
      const archive = archiver('zip');

      output.on('close', function() {
          res.download(zipFilePath, function(err) {
              if (err) {
                  console.error('İndirme işlemi başarısız:', err);
              }
              fs.unlink(zipFilePath, (err) => {
                  if (err) console.error('Zip dosyası silinemedi:', err);
              });
          });
      });

      archive.on('error', function(err) {
          console.error('Arşivleme hatası:', err);
          return res.status(500).json({ error: 'Zipping failed' });
      });

      archive.pipe(output);

      zipNames.forEach(file => {
          const filePath = path.join(uploadPath, file);
          if (fs.existsSync(filePath)) {
              archive.file(filePath, { name: file });
          } else {
              console.warn(`Dosya mevcut değil: ${filePath}`);
          }
      });

      archive.finalize();
      } else {
          res.json({ error: "Yetkiniz yok" });
      }
  };

	child.coveredMethods.push("uploadFile");
	child.uploadFile = function(req, res){
			child.handleFiles(req,res, function(error){
				if((!err && !error) || (err != null &&  error != null)){
					res.json({success:"images has been uploaded"})
				}else{
					res.json({error:error, err:err})
				}
			})
	}
	child.coveredMethods.push("handleFiles");
	child.handleFiles = function(req, res, next){
			if(req[child.singularName] && req[child.singularName].canEditByUser(req.user)){
				if (!fs.existsSync(path.resolve('uploads/' + child.singularName))){
					fs.mkdirSync(path.resolve('uploads/' + child.singularName));
				}
				if (!fs.existsSync(path.resolve('uploads/' + child.singularName + "/" + req[child.singularName].id))){
					fs.mkdirSync(path.resolve('uploads/' + child.singularName + "/" + req[child.singularName].id));
				}
				var needToSave = false

				if(req.files == null){
					req.files = {}
				}
				async.each(Object.keys(req.files), function(key, next){
					if(req[child.singularName].walk(key) == undefined || req[child.singularName].walk(key) == null){
						req[child.singularName].walk(key, [])
					}
					needToSave = true
					if(req.files[key].isArray() ){
						if(req[child.singularName].walk(key) == undefined || req[child.singularName].walk(key) == null){
							req[child.singularName].walk(key, [])
						}
						async.each(req.files[key], function(file, tick){
							file["dataPath"] = path.resolve('uploads/' + child.singularName + "/" + req[child.singularName].id + '/' + file.name)
							var item = req[child.singularName].walk(key);
							item.push(file.name)
							mv(file.newPath, file.dataPath, tick)
						}, next)
					}else {
						if(req[child.singularName].walk(key) == undefined || req[child.singularName].walk(key) == null){
							req[child.singularName].walk(key, {})
						}
						req.files[key]["dataPath"] = path.resolve('uploads/' + child.singularName + "/" + req[child.singularName].id + '/' + req.files[key].name)
						req[child.singularName].walk(key, req.files[key].name);
						mv(req.files[key].newPath, req.files[key].dataPath, next)
					}
				}, function(err){
					//EWLog(needToSave)
					if(needToSave){
						req[child.singularName].save(next)
					}else{
						next()
					}
				})
			}else{
				req.flash('info', 'Bu işlemi yapmak için yetkiniz yok');
				if(req.user){
					res.statusData = "Error"
					return res.redirect('/users/' + req.user.id);
				}else{
					res.statusData = "Error"
					return res.redirect('/login');
				}
			}
	}
	child.apify = function(funcName){
		var method = function(req, res){
			var argsPre = arguments.toArrayEW();
			res._redirect = res.redirect
			res.redirect = function(name){
				var data = {
					status: res.statusData,
					type:"redirect",
					name:name,
					model:res.model,
					flash:res.flashData
				}
				data[child.singularName] = res.model
				res.json(data);
			}
			res._render = res.redirect
			res.render = function(name, model){
				var data = {
					status:res.statusData,
					type:"render",
					name:name,
					model:model,
					flash:res.flashData
				}
				data[child.singularName] = res.model
				res.json(data);
			}
			res._flash = res.flash
			res.flash = function(name, message){
				if(res.flashData == undefined || res.flashData == null){
						res.flashData = []
				}
				res.flashData.push({name:name, message:message});
			}
			req._flash = req.flash
			req.flash = function(name, message){
				if(res.flashData == undefined || res.flashData == null){
					res.flashData = []
				}
				res.flashData.push({name:name, message:message});
			}
			child[funcName].apply(this, argsPre);
		}
		child[funcName + "API"] = function(req, res){
			var argsInner = arguments.toArrayEW();
			if(req.params[child.singularName + 'Id']){
				child.load(req, res, function(){
					method.apply(this, argsInner)
				}, req.params[child.singularName + 'Id'])
			}else if(req.body[child.singularName + 'Id']){
				child.load(req, res, function(){
					method.apply(this, argsInner)
				}, req.body[child.singularName + 'Id'])
			}else if(req.query[child.singularName + 'Id']){
				child.load(req, res, function(){
					method.apply(this, argsInner)
				}, req.query[child.singularName + 'Id'])
			}else{
				method.apply(this, argsInner)
			}
		}
	}
	/*
	child.apifyAllRequests = function(s){  // need function that encapsulated to have first arg as req and second arg as res
		for(var key in this){
			var obj = this[key];
			if(key != 'loadRelatedData' && typeof obj == "function" && !key.includes("API")){
				var params = getParamNames(obj);
				if(params[0] == "req" && params[1] == "res" && params.length == 2){
					this.apify(key);
				}
			}
		}
	};
	child.apifyAllRequests();*/


	child.acceptCheck = function(funcName){
		child[funcName] = child[funcName].goAOP()
		child[funcName].preCall = function(req, res, n){
	 		if(!res.errors){
	 			res.errors = []
	 		}
			if(req.accepts('html')){
			}else if(req.accepts('json')){
				res._redirect = res.redirect
				res.redirect = function(name){
					var data = {
						status: res.statusData,
						type:"redirect",
						name:name,
						model:res.model,
						flash:res.flashData
					}
					data[child.singularName] = res.model
					res.json(data);
				}
				res._render = res.redirect
				res.render = function(name, model){
					var data = {
						status:res.statusData,
						type:"render",
						name:name,
						model:model,
						flash:res.flashData
					}
					data[child.singularName] = res.model
					res.json(data);
				}
				res._flash = res.flash
				res.flash = function(name, message){
					if(res.flashData == undefined || res.flashData == null){
							res.flashData = []
					}
					res.flashData.push({name:name, message:message});
				}
				req._flash = req.flash
				req.flash = function(name, message){
					if(res.flashData == undefined || res.flashData == null){
						res.flashData = []
					}
					res.flashData.push({name:name, message:message});
				}
			}


            var argsPre = arguments.toArrayEW();
            var next = argsPre[argsPre.length -1];
            next.apply(this,argsPre);
		}
	}
	child.acceptCheckAllRequests = function(s){  // need function that encapsulated to have first arg as req and second arg as res
		for(var key in this){
			var obj = this[key];
			if(key != 'loadRelatedData' && typeof obj == "function" && !key.includes("API")){
				var params = getParamNames(obj);
				if(params[0] == "req" && params[1] == "res" && params.length == 2){
					//EWLog(child.pluralName, key)
					this.apify(key);
					this.acceptCheck(key);
				}
			}
		}
	};
	child.apifyAllRequests = child.apifyAllRequests
};
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var ARGUMENT_NAMES = /([^\s,]+)/g;

function getParamNames (func) {
	var fnStr = func.toString().replace(STRIP_COMMENTS, '');
	var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
	if(result === null)
		result = [];
	return result;
}
