// import type { Core } from '@strapi/strapi';
import path from 'path';
import fs from 'fs';
import { errors } from '@strapi/utils';

const PROTECTED_SUBMISSIONS = {
  'api::contact-submission.contact-submission': {
    label: 'Contact submissions',
    list: ['id', 'fullName', 'email', 'subject', 'message', 'createdAt'],
    edit: [
      [{ name: 'fullName', size: 6 }, { name: 'email', size: 6 }],
      [{ name: 'subject', size: 12 }],
      [{ name: 'message', size: 12 }],
    ],
    fields: ['fullName', 'email', 'subject', 'message'],
  },
  'api::hospitality-inquiry.hospitality-inquiry': {
    label: 'Hospitality inquiries',
    list: ['id', 'fullName', 'email', 'enquiryType', 'message', 'createdAt'],
    edit: [
      [{ name: 'fullName', size: 6 }, { name: 'email', size: 6 }],
      [{ name: 'enquiryType', size: 12 }],
      [{ name: 'message', size: 12 }],
    ],
    fields: ['fullName', 'email', 'enquiryType', 'message'],
  },
  'api::newsletter-subscriber.newsletter-subscriber': {
    label: 'Newsletter subscribers',
    list: ['id', 'email', 'createdAt'],
    edit: [[{ name: 'email', size: 12 }]],
    fields: ['email'],
  },
  'api::wedding-inquiry.wedding-inquiry': {
    label: 'Wedding inquiries',
    list: [
      'id',
      'fullName',
      'email',
      'mobile',
      'eventType',
      'eventBudget',
      'eventDate',
      'eventTime',
      'requirements',
      'createdAt',
    ],
    edit: [
      [{ name: 'fullName', size: 6 }, { name: 'email', size: 6 }],
      [{ name: 'mobile', size: 4 }, { name: 'eventType', size: 4 }, { name: 'eventBudget', size: 4 }],
      [{ name: 'eventDate', size: 6 }, { name: 'eventTime', size: 6 }],
      [{ name: 'requirements', size: 12 }],
    ],
    fields: ['fullName', 'email', 'mobile', 'eventType', 'eventBudget', 'eventDate', 'eventTime', 'requirements'],
  },
} as const;

const PROTECTED_SUBMISSION_UIDS = new Set(Object.keys(PROTECTED_SUBMISSIONS));
const UNIQUE_EMAIL_SUBMISSION_UIDS = new Set([
  'api::newsletter-subscriber.newsletter-subscriber',
]);

const normalizeEmail = (value: unknown) =>
  typeof value === 'string' ? value.trim().toLowerCase() : '';

const readOnlyMetadatas = (currentMetadatas: Record<string, any>, fields: readonly string[]) =>
  fields.reduce<Record<string, any>>((metadatas, field) => {
    metadatas[field] = {
      ...currentMetadatas[field],
      edit: {
        label: field,
        description: '',
        placeholder: '',
        visible: true,
        ...currentMetadatas[field]?.edit,
        editable: false,
      },
      list: {
        label: field,
        searchable: true,
        sortable: true,
        ...currentMetadatas[field]?.list,
      },
    };
    return metadatas;
  }, {});

async function enforceProtectedSubmissionAdminViews(strapi: any) {
  const contentTypeService = strapi.plugin('content-manager').service('content-types');

  for (const [uid, config] of Object.entries(PROTECTED_SUBMISSIONS)) {
    const contentType = contentTypeService.findContentType(uid);
    if (!contentType) continue;

    const current = await contentTypeService.findConfiguration(contentType);
    await contentTypeService.updateConfiguration(contentType, {
      ...current,
      layouts: {
        ...current.layouts,
        list: config.list,
        edit: config.edit,
      },
      metadatas: {
        ...current.metadatas,
        ...readOnlyMetadatas(current.metadatas, config.fields),
      },
    });
  }
}

function descriptionMetadatas(currentMetadatas: Record<string, any>, attributes: Record<string, any>) {
  return Object.entries(attributes).reduce<Record<string, any>>((metadatas, [field, attribute]) => {
    const description = attribute?.description;
    if (typeof description !== 'string' || description.trim() === '') {
      return metadatas;
    }

    metadatas[field] = {
      ...currentMetadatas[field],
      edit: {
        label: field,
        placeholder: '',
        visible: true,
        editable: true,
        ...currentMetadatas[field]?.edit,
        description,
      },
      list: {
        label: field,
        ...currentMetadatas[field]?.list,
      },
    };
    return metadatas;
  }, {});
}

async function syncAdminFieldDescriptions(strapi: any) {
  const contentTypeService = strapi.plugin('content-manager').service('content-types');
  const componentService = strapi.plugin('content-manager').service('components');

  for (const contentType of Object.values(strapi.contentTypes) as any[]) {
    if (!contentType?.uid?.startsWith('api::')) continue;

    const descriptions = descriptionMetadatas({}, contentType.attributes ?? {});
    if (Object.keys(descriptions).length === 0) continue;

    const current = await contentTypeService.findConfiguration(contentType);
    await contentTypeService.updateConfiguration(contentType, {
      ...current,
      metadatas: {
        ...current.metadatas,
        ...descriptionMetadatas(current.metadatas, contentType.attributes ?? {}),
      },
    });
  }

  for (const component of Object.values(strapi.components) as any[]) {
    const descriptions = descriptionMetadatas({}, component.attributes ?? {});
    if (Object.keys(descriptions).length === 0) continue;

    const current = await componentService.findConfiguration(component);
    await componentService.updateConfiguration(component, {
      ...current,
      metadatas: {
        ...current.metadatas,
        ...descriptionMetadatas(current.metadatas, component.attributes ?? {}),
      },
    });
  }
}

function registerProtectedSubmissionDocumentGuard(strapi: any) {
  strapi.documents.use(async (context, next) => {
    if (!PROTECTED_SUBMISSION_UIDS.has(context.uid)) {
      return next();
    }

    const config = PROTECTED_SUBMISSIONS[context.uid as keyof typeof PROTECTED_SUBMISSIONS];

    if (['update', 'delete', 'clone', 'publish', 'unpublish', 'discardDraft'].includes(context.action)) {
      throw new errors.ForbiddenError(`${config.label} are read-only.`);
    }

    if (context.action === 'create') {
      const email = normalizeEmail(context.params?.data?.email);
      if (email) {
        context.params.data.email = email;
      }

      if (email && UNIQUE_EMAIL_SUBMISSION_UIDS.has(context.uid)) {
        const existing = await strapi.db.query(context.uid).findOne({
          where: { email: { $eqi: email } },
        });

        if (existing) {
          throw new errors.ValidationError('This email is already registered.');
        }
      }
    }

    return next();
  });
}

export default {
  /**
   * An asynchronous register function that runs before
   * your application is initialized.
   *
   * This gives you an opportunity to extend code.
   */
  register(/* { strapi }: { strapi: Core.Strapi } */) {},

  /**
   * An asynchronous bootstrap function that runs before
   * your application gets started.
   *
   * This gives you an opportunity to set up your data model,
   * run jobs, or perform some special logic.
   */
  async bootstrap({ strapi }) {
    try {
      registerProtectedSubmissionDocumentGuard(strapi);
      await enforceProtectedSubmissionAdminViews(strapi);
      await syncAdminFieldDescriptions(strapi);

      const publicRole = await strapi.db.query('plugin::users-permissions.role').findOne({
        where: { type: 'public' },
      });

      // Grant public read access (find / findOne) to EVERY API content type.
      // Without this, endpoints like /api/footer, /api/homepage, ... return 403,
      // which is what breaks image/data fetching on the Next.js frontend.
      if (publicRole) {
        const actions: string[] = [];
        for (const [uid, ct] of Object.entries(strapi.contentTypes)) {
          if (!uid.startsWith('api::')) continue;
          actions.push(`${uid}.find`);
          if ((ct as any).kind === 'collectionType') {
            actions.push(`${uid}.findOne`);
          }
        }

        for (const action of actions) {
          const existing = await strapi.db.query('plugin::users-permissions.permission').findOne({
            where: { role: publicRole.id, action },
          });
          if (!existing) {
            await strapi.db.query('plugin::users-permissions.permission').create({
              data: { role: publicRole.id, action },
            });
            strapi.log.info(`Granted public permission for: ${action}`);
          }
        }
      }

      // Seed Header Links
      const header = await strapi.documents('api::header.header').findFirst({
        populate: ['navLinks']
      });

      const payload = {
        navLinks: [
          { label: 'About us', url: '/about', isBold: true },
          { label: 'Our companies', url: '#companies', hasDropdown: true },
          { label: 'Career', url: '/careers' },
          { label: 'Newsletter', url: '/newsletter' }
        ],
        companyLinks: [
          { label: 'MGM SAFL', url: '/safl' },
          { label: 'MGM Muthu Hotels', url: '/hospitality' },
          { label: 'MGM Dizzee World', url: '/entertainment' },
          { label: 'MGM Vital Green Energy', url: '/green-energy' },
          { label: 'MGM Anand Transport', url: '/logistics' },
          { label: 'Vital Industries', url: '/vital-industries' },
          { label: 'MGM Weddings', url: '/wedding-collective' }
        ],
        mobileMenuLinks: [
          { label: 'Home', url: '/' },
          { label: 'About us', url: '/about' },
          { label: 'MGM SAFL', url: '/safl' },
          { label: 'MGM Dizzee World', url: '/entertainment' },
          { label: 'MGM Muthu Hotels', url: '/hospitality' },
          { label: 'MGM Vital Green Energy', url: '/green-energy' },
          { label: 'MGM Anand Transport', url: '/logistics' },
          { label: 'Vital Industries', url: '/vital-industries' },
          { label: 'Careers', url: '/careers' },
          { label: 'MGM Weddings', url: '/wedding-collective' },
          { label: 'Newsletter', url: '/newsletter' },
          { label: 'Contact us', url: '/contact' }
        ]
      };

      if (!header) {
        await strapi.documents('api::header.header').create({
          data: payload
        });
        strapi.log.info('Successfully created and seeded header links.');
      } else if (!header.navLinks || header.navLinks.length === 0) {
        await strapi.documents('api::header.header').update({
          documentId: header.documentId,
          data: payload
        });
        strapi.log.info('Successfully updated header links.');
      }

      // Seed Footer
      // The footer single type has required media (logo_1600x475 + icon_1x1 on every
      // social/contact component), so a valid record cannot exist without those assets.
      // We upload the bundled assets into the media library, then link them to a footer record.
      const assetsDir = path.resolve(process.cwd(), '..', 'public', 'assets');
      const footerAsset = (rel: string) => path.join(assetsDir, rel);

      const uploadService = strapi.plugin('upload').service('upload');
      const findFileByName = async (name: string) =>
        strapi.db.query('plugin::upload.file').findOne({ where: { name } });

      const uploadAsset = async (
        absPath: string,
        name: string,
        mime: string,
      ): Promise<any | null> => {
        if (!fs.existsSync(absPath)) {
          strapi.log.warn(`[footer-seed] asset not found, skipping: ${absPath}`);
          return null;
        }
        const existing = await findFileByName(name);
        if (existing) return existing;
        const stats = fs.statSync(absPath);
        const [uploaded] = await uploadService.upload({
          data: { fileInfo: { name } },
          files: {
            filepath: absPath,
            originalFilename: path.basename(absPath),
            mimetype: mime,
            size: stats.size,
          },
        });
        return uploaded ?? null;
      };

      const footer = await strapi
        .documents('api::footer.footer')
        .findFirst({ populate: ['socialLinks', 'contactItems', 'logo_1600x475'] });

      if (!footer) {
        try {
          const logo = await uploadAsset(
            footerAsset('MGM_Logo.png'),
            'Footer Logo',
            'image/png',
          );
          const socialIcons = await Promise.all([
            uploadAsset(footerAsset('footer/icon-facebook.svg'), 'Footer Icon Facebook', 'image/svg+xml'),
            uploadAsset(footerAsset('footer/icon-twitter.svg'), 'Footer Icon Twitter', 'image/svg+xml'),
            uploadAsset(footerAsset('footer/icon-linkedin.svg'), 'Footer Icon LinkedIn', 'image/svg+xml'),
            uploadAsset(footerAsset('footer/icon-instagram.svg'), 'Footer Icon Instagram', 'image/svg+xml'),
          ]);
          const contactIcons = await Promise.all([
            uploadAsset(footerAsset('footer/icon-location.svg'), 'Footer Icon Location', 'image/svg+xml'),
            uploadAsset(footerAsset('footer/icon-phone.svg'), 'Footer Icon Phone', 'image/svg+xml'),
            uploadAsset(footerAsset('footer/icon-mail.svg'), 'Footer Icon Mail', 'image/svg+xml'),
          ]);

          const socialLinks = [
            { icon_1x1: socialIcons[0]?.id, url: '' },
            { icon_1x1: socialIcons[1]?.id, url: '' },
            { icon_1x1: socialIcons[2]?.id, url: '' },
            { icon_1x1: socialIcons[3]?.id, url: '' },
          ].filter((s) => s.icon_1x1) as { icon_1x1: any; url: string }[];

          const contactItems = [
            { icon_1x1: contactIcons[0]?.id, value: 'MGM Group, Chennai, Tamil Nadu, India', href: '' },
            { icon_1x1: contactIcons[1]?.id, value: '+91 898 989 8989', href: 'tel:+918989898989' },
            { icon_1x1: contactIcons[2]?.id, value: 'info@mgmgroup.in', href: 'mailto:info@mgmgroup.in' },
          ].filter((c) => c.icon_1x1) as { icon_1x1: any; value: string; href: string }[];

          if (logo && socialLinks.length && contactItems.length) {
            await strapi.documents('api::footer.footer').create({
              data: {
                title: 'Footer',
                description:
                  'Building excellence across Entertainment, Hospitality, Manufacturing, and Logistics since 1963.',
                copyright: '© 2025 MGM Group. All rights reserved.',
                logo_1600x475: logo.id,
                socialLinks,
                contactItems,
              },
            });
            strapi.log.info('Successfully created and seeded footer.');
          } else {
            strapi.log.warn('Footer seed skipped: one or more assets failed to upload.');
          }
        } catch (fe) {
          strapi.log.error('Footer seed error:', fe);
        }
      }
    } catch (e) {
      strapi.log.error('Bootstrap error:', e);
    }
  },
};
