import type { Core } from '@strapi/strapi';
// @ts-ignore
import bcrypt from 'bcryptjs';

export default {
  register({ strapi }: { strapi: Core.Strapi }) {
    // Hide 'User' collection type from Content Manager sidebar
    if (strapi.contentTypes['plugin::users-permissions.user']) {
      strapi.contentTypes['plugin::users-permissions.user'].pluginOptions = {
        ...(strapi.contentTypes['plugin::users-permissions.user'].pluginOptions || {}),
        'content-manager': { visible: false },
      };
    }

    // Middleware to block Authors from publishing drafts while allowing them to unpublish
    strapi.server.use(async (ctx, next) => {
      const url = ctx.url || '';
      if (
        url.includes('/content-manager/') &&
        url.includes('api::blog.blog') &&
        (url.includes('/publish') || url.includes('/actions/publish')) &&
        ctx.method === 'POST'
      ) {
        const user = ctx.state?.user;
        if (user && user.roles) {
          const isAuthor = user.roles.some((r: any) => r.code === 'strapi-author');
          const isSuperAdmin = user.roles.some((r: any) => r.code === 'strapi-super-admin');
          const isEditor = user.roles.some((r: any) => r.code === 'strapi-editor');

          if (isAuthor && !isSuperAdmin && !isEditor) {
            const isUnpublish = ctx.request?.body?.discardDraft || url.includes('/unpublish') || ctx.query?.action === 'unpublish';
            if (!isUnpublish) {
              return ctx.forbidden('Authors are not permitted to publish draft articles. Please submit for Editor review.');
            }
          }
        }
      }
      await next();
    });
  },

  async bootstrap({ strapi }: { strapi: Core.Strapi }) {
    // 1. Enable Public Read Permissions for api::blog.blog & api::job-role.job-role
    try {
      const publicRole = await strapi.db.query('plugin::users-permissions.role').findOne({
        where: { type: 'public' },
      });

      if (publicRole) {
        const permissionsToGrant = [
          'api::blog.blog.find',
          'api::blog.blog.findOne',
          'api::job-role.job-role.find',
          'api::job-role.job-role.findOne',
        ];
        for (const action of permissionsToGrant) {
          const existingPermission = await strapi.db
            .query('plugin::users-permissions.permission')
            .findOne({
              where: { role: publicRole.id, action },
            });

          if (!existingPermission) {
            await strapi.db.query('plugin::users-permissions.permission').create({
              data: {
                action,
                role: publicRole.id,
              },
            });
          }
        }
        strapi.log.info('Public permissions for Blog & Job Role APIs initialized.');
      }
    } catch (err) {
      strapi.log.warn('Could not set public permissions automatically:', err);
    }

    // 2. Fetch Strapi Admin Roles
    const superAdminRole = await strapi.db.query('admin::role').findOne({ where: { code: 'strapi-super-admin' } });
    const editorRole = await strapi.db.query('admin::role').findOne({ where: { code: 'strapi-editor' } });
    const authorRole = await strapi.db.query('admin::role').findOne({ where: { code: 'strapi-author' } });

    // Clean field list for Authors/Editors
    const contentVisibleFields = [
      'title',
      'slug',
      'category',
      'excerpt',
      'content',
      'coverImage',
      'approvalStatus',
      'reviewNotes',
      'approvalDate',
      'readTime',
      'publishDate',
      'tags',
      'metaTitle',
      'metaDescription',
      'keywords',
      'canonicalURL',
      'ogImage',
    ];
    const propertiesObj = JSON.stringify({ fields: contentVisibleFields });

    // 3. Grant Admin RBAC Permissions with Auto-Populated Fields Hidden from Form
    const grantRolePermissions = async (roleId: number, subject: string, actions: string[], isCreatorOnly = false, propObj = '{}') => {
      if (!roleId) return;
      for (const action of actions) {
        const conditions = isCreatorOnly ? ['admin::is-creator'] : [];
        const conditionsStr = JSON.stringify(conditions);
        const actionProperties = action === 'plugin::content-manager.explorer.delete' ? '{}' : propObj;

        const existing = await strapi.db.connection('admin_permissions')
          .join('admin_permissions_role_lnk', 'admin_permissions.id', 'admin_permissions_role_lnk.permission_id')
          .where({
            'admin_permissions.action': action,
            'admin_permissions.subject': subject,
            'admin_permissions_role_lnk.role_id': roleId,
          })
          .first();

        if (!existing) {
          const inserted = await strapi.db.connection('admin_permissions')
            .insert({
              action,
              subject,
              properties: actionProperties,
              conditions: conditionsStr,
            })
            .returning('id');

          const rawId = Array.isArray(inserted) ? inserted[0] : inserted;
          const permId = (typeof rawId === 'object' && rawId !== null) ? (rawId.id || rawId) : rawId;

          await strapi.db.connection('admin_permissions_role_lnk').insert({
            permission_id: Number(permId),
            role_id: roleId,
          });
          strapi.log.info(`Granted RBAC ${action} on ${subject} to role ID ${roleId}`);
        } else {
          await strapi.db.connection('admin_permissions')
            .where({ id: existing.permission_id })
            .update({
              properties: actionProperties,
              conditions: conditionsStr,
            });
        }
      }
    };

    // Grant Upload / Media Library permissions to Author & Editor roles
    const grantUploadPermissions = async (roleId: number) => {
      if (!roleId) return;
      const uploadActions = [
        'plugin::upload.assets.create',
        'plugin::upload.assets.read',
        'plugin::upload.assets.update',
        'plugin::upload.assets.download',
        'plugin::upload.read',
      ];
      for (const action of uploadActions) {
        const existing = await strapi.db.connection('admin_permissions')
          .join('admin_permissions_role_lnk', 'admin_permissions.id', 'admin_permissions_role_lnk.permission_id')
          .where({
            'admin_permissions.action': action,
            'admin_permissions_role_lnk.role_id': roleId,
          })
          .first();

        if (!existing) {
          const inserted = await strapi.db.connection('admin_permissions')
            .insert({
              action,
              subject: null,
              properties: '{}',
              conditions: '[]',
            })
            .returning('id');

          const rawId = Array.isArray(inserted) ? inserted[0] : inserted;
          const permId = (typeof rawId === 'object' && rawId !== null) ? (rawId.id || rawId) : rawId;

          await strapi.db.connection('admin_permissions_role_lnk').insert({
            permission_id: Number(permId),
            role_id: roleId,
          });
          strapi.log.info(`Granted Media Upload permission ${action} to role ID ${roleId}`);
        }
      }
    };

    if (authorRole) {
      await grantRolePermissions(authorRole.id, 'api::blog.blog', [
        'plugin::content-manager.explorer.create',
        'plugin::content-manager.explorer.read',
        'plugin::content-manager.explorer.update',
        'plugin::content-manager.explorer.publish',
      ], true, propertiesObj);
      await grantRolePermissions(authorRole.id, 'api::job-role.job-role', [
        'plugin::content-manager.explorer.create',
        'plugin::content-manager.explorer.read',
        'plugin::content-manager.explorer.update',
        'plugin::content-manager.explorer.publish',
      ], false, '{}');
      await grantUploadPermissions(authorRole.id);
    }

    if (editorRole) {
      await grantRolePermissions(editorRole.id, 'api::blog.blog', [
        'plugin::content-manager.explorer.create',
        'plugin::content-manager.explorer.read',
        'plugin::content-manager.explorer.update',
        'plugin::content-manager.explorer.publish',
      ], false, propertiesObj);
      await grantRolePermissions(editorRole.id, 'api::job-role.job-role', [
        'plugin::content-manager.explorer.create',
        'plugin::content-manager.explorer.read',
        'plugin::content-manager.explorer.update',
        'plugin::content-manager.explorer.publish',
      ], false, '{}');
      await grantUploadPermissions(editorRole.id);
    }

    // 4. Provision Strapi Admin Users with Valid Bcrypt Hashes and Admin Roles
    const adminUserDefs = [
      {
        email: 'admin@cavininfotech.com',
        firstname: 'Cavin',
        lastname: 'Admin',
        designation: 'Superuser & Infrastructure Lead',
        roleId: superAdminRole?.id || 1,
      },
      {
        email: 'arvindh@cavininfotech.com',
        firstname: 'Dr. Arvindh',
        lastname: 'Ramachandran',
        designation: 'Chief AI Architect & Head of Data Engineering',
        roleId: authorRole?.id || 3,
      },
      {
        email: 'siddharth@cavininfotech.com',
        firstname: 'Siddharth',
        lastname: 'Narayanan',
        designation: 'VP of Smart Factory & IIoT Solutions',
        roleId: authorRole?.id || 3,
      },
      {
        email: 'priya@cavininfotech.com',
        firstname: 'Priya S.',
        lastname: 'Venkatesh',
        designation: 'Lead Immersive UX & Spatial Computing Strategist',
        roleId: authorRole?.id || 3,
      },
      {
        email: 'vikram@cavininfotech.com',
        firstname: 'Vikram',
        lastname: 'Sen',
        designation: 'Senior Editor - Industrial Operations & OT Tech',
        roleId: editorRole?.id || 2,
      },
      {
        email: 'meera@cavininfotech.com',
        firstname: 'Meera',
        lastname: 'Krishnan',
        designation: 'Senior Editor - Enterprise Software & Cloud',
        roleId: editorRole?.id || 2,
      },
    ];

    const hashedPassword = await bcrypt.hash('CavinPass2026!', 10);
    const userMap: Record<string, any> = {};

    for (const uDef of adminUserDefs) {
      let user = await strapi.db.query('admin::user').findOne({
        where: { email: uDef.email },
        populate: ['roles'],
      });

      if (!user) {
        user = await strapi.db.query('admin::user').create({
          data: {
            email: uDef.email,
            firstname: uDef.firstname,
            lastname: uDef.lastname,
            password: hashedPassword,
            isActive: true,
            blocked: false,
            roles: [uDef.roleId],
          },
        });
        strapi.log.info(`Created Strapi Admin User: ${uDef.firstname} ${uDef.lastname} (${uDef.email})`);
      } else {
        if (!user.password.startsWith('$2')) {
          await strapi.db.query('admin::user').update({
            where: { id: user.id },
            data: { password: hashedPassword },
          });
        }
        if (!user.roles || user.roles.length === 0) {
          await strapi.db.query('admin::user').update({
            where: { id: user.id },
            data: { roles: [uDef.roleId] },
          });
        }
      }

      const linkCount = await strapi.db.connection('admin_users_roles_lnk').where({ user_id: user.id }).count('* as c');
      const countVal = Array.isArray(linkCount) ? (linkCount[0]?.c || linkCount[0]?.['count(*)']) : 0;
      if (Number(countVal) === 0) {
        await strapi.db.connection('admin_users_roles_lnk').insert({
          user_id: user.id,
          role_id: uDef.roleId,
          role_ord: 1,
          user_ord: 1,
        });
      }

      userMap[uDef.email] = {
        ...user,
        designation: uDef.designation,
        fullName: `${uDef.firstname} ${uDef.lastname}`,
      };
    }

    // 5. Seed Default Available Job Roles if Collection is empty
    try {
      const existingRolesCount = await strapi.db.query('api::job-role.job-role').count();
      if (existingRolesCount === 0) {
        const jobRoleDefs = [
          {
            title: 'Lead AI & Data Architect',
            department: 'AI & Analytics',
            type: 'Full-Time',
            location: 'Hybrid / Chennai',
            description: 'Lead design and execution of scalable AI, machine learning pipelines, and data architectures.',
            requirements: '8+ years in AI/ML, PyTorch/TensorFlow, Cloud Architectures, Distributed Data Systems.',
            isActive: true,
            publishedAt: new Date(),
          },
          {
            title: 'Senior IIoT & Smart Factory Specialist',
            department: 'Industrial IoT',
            type: 'Full-Time',
            location: 'On-Site / Chennai',
            description: 'Build enterprise IIoT platforms, sensor networks, and edge computing for modern smart factories.',
            requirements: '5+ years in IIoT, MQTT/OPC-UA, SCADA integration, Edge AI.',
            isActive: true,
            publishedAt: new Date(),
          },
          {
            title: 'Spatial Computing & MR UX Designer',
            department: 'AR/VR & Immersive Tech',
            type: 'Full-Time',
            location: 'Hybrid',
            description: 'Design next-gen spatial UX, mixed reality interfaces, and 3D digital twin visualizations.',
            requirements: 'Spatial UX, Unity/Unreal, Figma 3D, WebXR.',
            isActive: true,
            publishedAt: new Date(),
          },
          {
            title: 'Cloud Infrastructure & DevOps Engineer',
            department: 'Enterprise Cloud',
            type: 'Full-Time',
            location: 'Remote / Hybrid',
            description: 'Manage high-availability multi-cloud infrastructure, Kubernetes clusters, and automated CI/CD pipelines.',
            requirements: 'Kubernetes, Terraform, AWS/GCP, Zero-Trust Security.',
            isActive: true,
            publishedAt: new Date(),
          },
        ];

        for (const roleData of jobRoleDefs) {
          await strapi.db.query('api::job-role.job-role').create({ data: roleData });
          strapi.log.info(`Seeded Job Role: ${roleData.title}`);
        }
      }
    } catch (jobSeedErr) {
      strapi.log.warn('Job Role seeding note:', jobSeedErr);
    }
  },
};
