import {inject} from '@loopback/core';
import {
  Count,
  CountSchema,
  Filter,
  FilterExcludingWhere,
  repository,
  Where,
} from '@loopback/repository';
import {
  del,
  get,
  getModelSchemaRef,
  param,
  patch,
  post,
  Request,
  requestBody,
  response,
  RestBindings
} from '@loopback/rest';
import fs from 'fs';
import multer from 'multer';
import path from 'path';
import {URL} from '../config/constants';
import {AdsManagement} from '../models';
import {AdsManagementRepository} from '../repositories';
const BASE_URL = URL;

// --------- Configure Upload Directory ----------
const uploadDir = path.join(__dirname, '../../uploads/ads');
if (!fs.existsSync(uploadDir)) {
  fs.mkdirSync(uploadDir, {recursive: true});
}

const storage = multer.diskStorage({
  destination: function (_req, _file, cb) {
    cb(null, uploadDir);
  },
  filename: function (_req, file, cb) {
    cb(null, `${Date.now()}-${file.originalname}`);
  },
});

const upload = multer({storage});

export class AdsManagementController {
  constructor(
    @repository(AdsManagementRepository)
    public adsManagementRepository: AdsManagementRepository,
  ) { }

  // ---------- CREATE with image ----------
  @post('/ads-managements')
  @response(200, {
    description: 'Create ad with image',
    content: {'application/json': {schema: getModelSchemaRef(AdsManagement)}},
  })
  async createWithFile(
    @requestBody.file()
    request: Request,
    @inject(RestBindings.Http.RESPONSE) response: any,
  ): Promise<AdsManagement> {
    return new Promise<AdsManagement>((resolve, reject) => {
      // eslint-disable-next-line @typescript-eslint/no-misused-promises
      upload.single('adsPhoto')(request, response, async (err: any) => {
        if (err) return reject(err);

        const file = (request as any).file;
        const fields = (request as any).body;

        try {
          const newAd = await this.adsManagementRepository.create({
            adsTitle: fields.adsTitle,
            publish_Fag: 1,
            fksellerId: parseInt(fields.fksellerId),
            fkadsTypeId: parseInt(fields.fkadsTypeId),
            adsStartDate: fields.adsStartDate ? new Date(fields.adsStartDate) : undefined,
            adsEndDate: fields.adsEndDate ? new Date(fields.adsEndDate) : undefined,
            adsPhoto: file ? `${BASE_URL}/uploads/ads/${file.filename}` : undefined,
            lastChanged: new Date().toISOString(),
          });
          resolve(newAd);
        } catch (e) {
          reject(e);
        }
      });
    });
  }

  // ---------- COUNT ----------
  @get('/ads-managements/count')
  @response(200, {
    description: 'AdsManagement model count',
    content: {'application/json': {schema: CountSchema}},
  })
  async count(
    @param.where(AdsManagement) where?: Where<AdsManagement>,
  ): Promise<Count> {
    return this.adsManagementRepository.count(where);
  }

  // ---------- FIND ----------
  @get('/ads-managements')
  @response(200, {
    description: 'Array of AdsManagement model instances',
    content: {
      'application/json': {
        schema: {
          type: 'array',
          items: getModelSchemaRef(AdsManagement, {includeRelations: true}),
        },
      },
    },
  })
  async find(
    @param.filter(AdsManagement) filter?: Filter<AdsManagement>,
  ): Promise<AdsManagement[]> {
    return this.adsManagementRepository.find({
      ...filter,
      include: [
        {
          relation: 'adsType',
          scope: {
            fields: {
              adsTypeId: true,
              adstypeName: true,
            },
          },
        },
      ],
    });
  }

  // ---------- FIND BY ID ----------
  @get('/ads-managements/{id}')
  @response(200, {
    description: 'AdsManagement model instance',
    content: {
      'application/json': {
        schema: getModelSchemaRef(AdsManagement, {includeRelations: true}),
      },
    },
  })
  async findById(
    @param.path.number('id') id: number,
    @param.filter(AdsManagement, {exclude: 'where'})
    filter?: FilterExcludingWhere<AdsManagement>,
  ): Promise<AdsManagement> {
    return this.adsManagementRepository.findById(id, {
      ...filter,
      include: [
        {
          relation: 'adsType',
          scope: {
            fields: {
              adsTypeId: true,
              adstypeName: true,
            },
          },
        },
      ],
    });
  }

  // ---------- UPDATE with image ----------
  @patch('/ads-managements/{id}')
  @response(204, {
    description: 'AdsManagement PATCH success',
  })
  async updateByIdWithFile(
    @param.path.number('id') id: number,
    @requestBody.file()
    request: Request,
    @inject(RestBindings.Http.RESPONSE) response: any,
  ): Promise<void> {
    return new Promise<void>((resolve, reject) => {
      // eslint-disable-next-line @typescript-eslint/no-misused-promises
      upload.single('adsPhoto')(request, response, async (err: any) => {
        if (err) return reject(err);

        const file = (request as any).file;
        const fields = (request as any).body;

        try {
          // Get existing record
          const existingAd = await this.adsManagementRepository.findById(id);

          await this.adsManagementRepository.updateById(id, {
            adsTitle: fields.adsTitle,
            publish_Fag: 1,
            fksellerId: parseInt(fields.fksellerId),
            fkadsTypeId: parseInt(fields.fkadsTypeId),
            adsStartDate: fields.adsStartDate || null,
            adsEndDate: fields.adsEndDate || null,
            adsPhoto: file
              ? `${BASE_URL}/uploads/ads/${file.filename}`
              : existingAd.adsPhoto, // <-- keep old photo if not uploading new
            lastChanged: new Date().toISOString(),
          });

          resolve();
        } catch (e) {
          reject(e);
        }
      });
    });
  }


  // ---------- DELETE ----------
  @del('/ads-managements/{id}')
  @response(204, {
    description: 'AdsManagement DELETE success',
  })
  async deleteById(@param.path.number('id') id: number): Promise<void> {
    await this.adsManagementRepository.deleteById(id);
  }

  @patch('/ads-managements/soft-delete/{id}')
  async softDeleteAd(
    @param.path.number('id') id: number,
  ): Promise<void> {
    await this.adsManagementRepository.updateById(id, {
      isActive: 0,
      lastChanged: new Date().toISOString(),
    });
  }

}
