import FalukantService from '../services/falukantService.js';

function extractHashedUserId(req) {
    return req.headers?.userid;
}

class FalukantController {
    constructor() {
        this.service = FalukantService;

        // No-user endpoints
        this.randomFirstName = this._wrapNoUser(this.service.randomFirstName.bind(this.service), {
            successStatus: 200,
            transform: gender => ({ name: gender })
        });
        this.randomLastName = this._wrapNoUser(this.service.randomLastName.bind(this.service), {
            successStatus: 200,
            transform: name => ({ name })
        });

        // User-scoped endpoints
        this.getUser = this._wrapWithUser((userId) => this.service.getUser(userId));
        this.createUser = this._wrapWithUser((userId, req) => {
            const { gender, firstname, lastname } = req.body;
            return this.service.createUser(userId, gender, firstname, lastname);
        }, { successStatus: 201 });

        this.getInfo = this._wrapWithUser((userId) => this.service.getInfo(userId));
        this.getBranches = this._wrapWithUser((userId) => this.service.getBranches(userId));
        this.createBranch = this._wrapWithUser((userId, req) => this.service.createBranch(userId, req.body.cityId, req.body.branchTypeId));
        this.getBranchTypes = this._wrapWithUser((userId) => this.service.getBranchTypes(userId));
        this.getBranch = this._wrapWithUser((userId, req) => this.service.getBranch(userId, req.params.branch));
        this.upgradeBranch = this._wrapWithUser((userId, req) => this.service.upgradeBranch(userId, req.body.branchId));
        this.createProduction = this._wrapWithUser((userId, req) => {
            const { branchId, productId, quantity } = req.body;
            return this.service.createProduction(userId, branchId, productId, quantity);
        }, { successStatus: 201 });
        this.getProduction = this._wrapWithUser((userId, req) => this.service.getProduction(userId, req.params.branchId));
        this.getStock = this._wrapWithUser((userId, req) => this.service.getStock(userId, req.params.branchId || null));
        this.createStock = this._wrapWithUser((userId, req) => {
            const { branchId, stockTypeId, stockSize } = req.body;
            return this.service.createStock(userId, branchId, stockTypeId, stockSize);
        }, { successStatus: 201 });
        this.getProducts = this._wrapWithUser((userId) => this.service.getProducts(userId));
        this.getInventory = this._wrapWithUser((userId, req) => this.service.getInventory(userId, req.params.branchId));
        this.sellProduct = this._wrapWithUser((userId, req) => {
            const { branchId, productId, quality, quantity } = req.body;
            return this.service.sellProduct(userId, branchId, productId, quality, quantity);
        }, { successStatus: 201 });
        this.sellAllProducts = this._wrapWithUser((userId, req) => {
            const { branchId } = req.body;
            return this.service.sellAllProducts(userId, branchId);
        }, { successStatus: 201 });
        this.moneyHistory = this._wrapWithUser((userId, req) => {
            let { page, filter } = req.body;
            if (!page) page = 1;
            return this.service.moneyHistory(userId, page, filter);
        });
        this.getStorage = this._wrapWithUser((userId, req) => this.service.getStorage(userId, req.params.branchId));
        this.buyStorage = this._wrapWithUser((userId, req) => {
            const { branchId, amount, stockTypeId } = req.body;
            return this.service.buyStorage(userId, branchId, amount, stockTypeId);
        }, { successStatus: 201 });
        this.sellStorage = this._wrapWithUser((userId, req) => {
            const { branchId, amount, stockTypeId } = req.body;
            return this.service.sellStorage(userId, branchId, amount, stockTypeId);
        }, { successStatus: 202 });

        this.getStockTypes = this._wrapSimple(() => this.service.getStockTypes());
        this.getStockOverview = this._wrapSimple(() => this.service.getStockOverview());
        this.getAllProductions = this._wrapWithUser((userId) => this.service.getAllProductions(userId));

        this.getDirectorProposals = this._wrapWithUser((userId, req) => {
            console.log('🔍 getDirectorProposals called with userId:', userId, 'branchId:', req.body.branchId);
            return this.service.getDirectorProposals(userId, req.body.branchId);
        });
        this.convertProposalToDirector = this._wrapWithUser((userId, req) => this.service.convertProposalToDirector(userId, req.body.proposalId));
        this.getDirectorForBranch = this._wrapWithUser((userId, req) => this.service.getDirectorForBranch(userId, req.params.branchId));
        this.getAllDirectors = this._wrapWithUser((userId) => this.service.getAllDirectors(userId));
        this.updateDirector = this._wrapWithUser((userId, req) => {
            const { directorId, income } = req.body;
            return this.service.updateDirector(userId, directorId, income);
        });

        this.setSetting = this._wrapWithUser((userId, req) => {
            const { branchId, directorId, settingKey, value } = req.body;
            return this.service.setSetting(userId, branchId, directorId, settingKey, value);
        });

        this.getFamily = this._wrapWithUser(async (userId) => {
            const result = await this.service.getFamily(userId);
            if (!result) throw { status: 404, message: 'No family data found' };
            return result;
        });
        this.setHeir = this._wrapWithUser((userId, req) => this.service.setHeir(userId, req.body.childCharacterId));
        this.getPotentialHeirs = this._wrapWithUser((userId) => this.service.getPotentialHeirs(userId));
        this.selectHeir = this._wrapWithUser((userId, req) => this.service.selectHeir(userId, req.body.heirId));
        this.acceptMarriageProposal = this._wrapWithUser((userId, req) => this.service.acceptMarriageProposal(userId, req.body.proposalId));
        this.getGifts = this._wrapWithUser((userId) => {
            console.log('🔍 getGifts called with userId:', userId);
            return this.service.getGifts(userId);
        });
        this.getChildren = this._wrapWithUser((userId) => this.service.getChildren(userId));
        this.sendGift = this._wrapWithUser((userId, req) => this.service.sendGift(userId, req.body.giftId));

        this.getTitlesOfNobility = this._wrapWithUser((userId) => this.service.getTitlesOfNobility(userId));
        this.getHouseTypes = this._wrapWithUser((userId) => this.service.getHouseTypes(userId));
        this.getMoodAffect = this._wrapWithUser((userId) => this.service.getMoodAffect(userId));
        this.getCharacterAffect = this._wrapWithUser((userId) => this.service.getCharacterAffect(userId));
        this.getUserHouse = this._wrapWithUser((userId) => this.service.getUserHouse(userId));
        this.getBuyableHouses = this._wrapWithUser((userId) => this.service.getBuyableHouses(userId));
        this.buyUserHouse = this._wrapWithUser((userId, req) => this.service.buyUserHouse(userId, req.body.houseId), { successStatus: 201 });

        this.getPartyTypes = this._wrapWithUser((userId) => this.service.getPartyTypes(userId));
        this.createParty = this._wrapWithUser((userId, req) => {
            const { partyTypeId, musicId, banquetteId, nobilityIds, servantRatio } = req.body;
            return this.service.createParty(userId, partyTypeId, musicId, banquetteId, nobilityIds, servantRatio);
        }, { successStatus: 201 });
        this.getParties = this._wrapWithUser((userId) => this.service.getParties(userId));

        this.getReputationActions = this._wrapWithUser((userId) => this.service.getReputationActions(userId));
        this.executeReputationAction = this._wrapWithUser((userId, req) => {
            const { actionTypeId } = req.body;
            return this.service.executeReputationAction(userId, actionTypeId);
        }, { successStatus: 201 });

        this.getNotBaptisedChildren = this._wrapWithUser((userId) => this.service.getNotBaptisedChildren(userId));
        this.baptise = this._wrapWithUser((userId, req) => {
            const { characterId: childId, firstName } = req.body;
            return this.service.baptise(userId, childId, firstName);
        });

        this.getEducation = this._wrapWithUser((userId) => this.service.getEducation(userId));
        this.sendToSchool = this._wrapWithUser((userId, req) => {
            const { item, student, studentId } = req.body;
            return this.service.sendToSchool(userId, item, student, studentId);
        });

        this.getBankOverview = this._wrapWithUser((userId) => this.service.getBankOverview(userId));
        this.getBankCredits = this._wrapWithUser((userId) => this.service.getBankCredits(userId));
        this.takeBankCredits = this._wrapWithUser((userId, req) => this.service.takeBankCredits(userId, req.body.height));

        this.getNobility = this._wrapWithUser((userId) => this.service.getNobility(userId));
        this.advanceNobility = this._wrapWithUser((userId) => this.service.advanceNobility(userId));

        this.getHealth = this._wrapWithUser((userId) => this.service.getHealth(userId));
        this.healthActivity = this._wrapWithUser((userId, req) => this.service.healthActivity(userId, req.body.measureTr));

        this.getPoliticsOverview = this._wrapWithUser((userId) => this.service.getPoliticsOverview(userId));
        this.getOpenPolitics = this._wrapWithUser((userId) => this.service.getOpenPolitics(userId));
        this.getElections = this._wrapWithUser((userId) => this.service.getElections(userId));
        this.vote = this._wrapWithUser((userId, req) => this.service.vote(userId, req.body.votes));
        this.applyForElections = this._wrapWithUser((userId, req) => this.service.applyForElections(userId, req.body.electionIds));

        this.getRegions = this._wrapWithUser((userId) => this.service.getRegions(userId));
    this.getBranchTaxes = this._wrapWithUser((userId, req) => this.service.getBranchTaxes(userId, req.params.branchId));
        this.getProductPriceInRegion = this._wrapWithUser((userId, req) => {
            const productId = parseInt(req.query.productId, 10);
            const regionId = parseInt(req.query.regionId, 10);
            if (Number.isNaN(productId) || Number.isNaN(regionId)) {
                throw new Error('productId and regionId are required');
            }
            return this.service.getProductPriceInRegion(userId, productId, regionId);
        });
        this.getProductPricesInRegionBatch = this._wrapWithUser((userId, req) => {
            const productIds = req.query.productIds;
            const regionId = parseInt(req.query.regionId, 10);
            if (!productIds || Number.isNaN(regionId)) {
                throw new Error('productIds (comma-separated) and regionId are required');
            }
            const productIdArray = productIds.split(',').map(id => parseInt(id.trim(), 10)).filter(id => !Number.isNaN(id));
            if (productIdArray.length === 0) {
                throw new Error('At least one valid productId is required');
            }
            return this.service.getProductPricesInRegionBatch(userId, productIdArray, regionId);
        });
        this.getProductPricesInCities = this._wrapWithUser((userId, req) => {
            const productId = parseInt(req.query.productId, 10);
            const currentPrice = parseFloat(req.query.currentPrice);
            const currentRegionId = req.query.currentRegionId ? parseInt(req.query.currentRegionId, 10) : null;
            if (Number.isNaN(productId) || Number.isNaN(currentPrice)) {
                throw new Error('productId and currentPrice are required');
            }
            return this.service.getProductPricesInCities(userId, productId, currentPrice, currentRegionId);
        });
        this.renovate = this._wrapWithUser((userId, req) => this.service.renovate(userId, req.body.element));
        this.renovateAll = this._wrapWithUser((userId) => this.service.renovateAll(userId));

        this.getUndergroundTypes = this._wrapWithUser((userId) => this.service.getUndergroundTypes(userId));
        this.getNotifications = this._wrapWithUser((userId) => this.service.getNotifications(userId));
        this.getAllNotifications = this._wrapWithUser((userId, req) => this.service.getAllNotifications(userId, req.query.page, req.query.size));
        this.markNotificationsShown = this._wrapWithUser((userId) => this.service.markNotificationsShown(userId), { successStatus: 202 });
        this.getUndergroundTargets = this._wrapWithUser((userId) => this.service.getPoliticalOfficeHolders(userId));

        this.searchUsers = this._wrapWithUser((userId, req) => {
            const q = req.query.q?.trim() || '';
            if (q.length < 1) return [];
            return this.service.searchUsers(userId, q);
        });

        this.createUndergroundActivity = this._wrapWithUser((userId, req) => {
            const payload = req.body;
            if (!payload.typeId) {
                throw { status: 400, message: 'typeId is required' };
            }
            if (payload.typeId === 'sabotage' && !payload.target) {
                throw { status: 400, message: 'target is required for sabotage' };
            }
            if (payload.typeId === 'corrupt_politician' && !payload.goal) {
                throw { status: 400, message: 'goal is required for corrupt_politician' };
            }
            return this.service.createUndergroundActivity(userId, payload);
        }, { successStatus: 201 });

        this.getUndergroundAttacks = this._wrapWithUser((userId, req) => {
            const direction = (req.query.direction || '').toLowerCase();
            return this.service.getUndergroundAttacks(userId).then(result => {
                if (direction === 'sent') return result.sent;
                if (direction === 'received') return result.received;
                return result; // both
            });
        });

        this.getVehicleTypes = this._wrapWithUser((userId) => this.service.getVehicleTypes(userId));
        this.buyVehicles = this._wrapWithUser(
            (userId, req) => this.service.buyVehicles(userId, req.body),
            { successStatus: 201 }
        );
        this.getVehicles = this._wrapWithUser(
            (userId, req) => this.service.getVehicles(userId, req.query.regionId)
        );
        this.createTransport = this._wrapWithUser(
            (userId, req) => this.service.createTransport(userId, req.body),
            { successStatus: 201 }
        );
        this.getTransportRoute = this._wrapWithUser(
            (userId, req) => this.service.getTransportRoute(userId, req.query)
        );
        this.getBranchTransports = this._wrapWithUser(
            (userId, req) => this.service.getBranchTransports(userId, req.params.branchId)
        );
        this.repairVehicle = this._wrapWithUser(
            (userId, req) => this.service.repairVehicle(userId, req.params.vehicleId),
            { successStatus: 200 }
        );
        this.repairAllVehicles = this._wrapWithUser(
            (userId, req) => this.service.repairAllVehicles(userId, req.body.vehicleIds),
            { successStatus: 200 }
        );

    }


    _wrapWithUser(fn, { successStatus = 200, postProcess } = {}) {
        return async (req, res) => {
            try {
                const hashedUserId = extractHashedUserId(req);
                if (!hashedUserId) {
                    return res.status(400).json({ error: 'Missing user identifier' });
                }
                const result = await fn(hashedUserId, req, res);
                const toSend = postProcess ? postProcess(result) : result;
                res.status(successStatus).json(toSend);
            } catch (error) {
                console.error('Controller error:', error);
                const status = error.status && typeof error.status === 'number' ? error.status : 500;
                res.status(status).json({ error: error.message || 'Internal error' });
            }
        };
    }

    _wrapSimple(fn, { successStatus = 200, postProcess } = {}) {
        return async (req, res) => {
            try {
                const result = await fn(req, res);
                const toSend = postProcess ? postProcess(result) : result;
                res.status(successStatus).json(toSend);
            } catch (error) {
                console.error('Controller error:', error);
                const status = error.status && typeof error.status === 'number' ? error.status : 500;
                res.status(status).json({ error: error.message || 'Internal error' });
            }
        };
    }

    _wrapNoUser(fn, { successStatus = 200, transform } = {}) {
        return async (req, res) => {
            try {
                let result;
                if (req.params && Object.keys(req.params).length) {
                    result = await fn(req.params.gender);
                } else {
                    result = await fn();
                }
                if (transform) result = transform(result);
                res.status(successStatus).json(result);
            } catch (error) {
                console.error('Controller error:', error);
                res.status(500).json({ error: error.message || 'Internal error' });
            }
        };
    }
}

export default FalukantController;
