const { Companies } = require("../models");
const { createList, createItem, getSiteId, getLists } = require("./microsoftGraph");
const { ensureFreshMsAccessToken } = require("../utils/msTokenService");
const { getAppOnlyAccessToken } = require("./appOnlyAuth");

/** SharePoint display name → spListMapping JSON key */
const LIST_DISPLAY_TO_MODULE = {
  NordSafe_Incidents: "incidents",
  NordSafe_RiskAssessments: "riskAssessments",
  NordSafe_JSA: "jsa",
  NordSafe_PTW: "permitToWork",
  NordSafe_HAZOP: "hazop",
  NordSafe_SDS: "sds",
  NordSafe_MinutesOfMeeting: "minutesOfMeeting",
};

/** API record types → spListMapping key (for sync) */
const RECORD_TYPE_TO_MODULE_KEY = {
  "case-investigations": "incidents",
  "risk-assessment": "riskAssessments",
  "job-safety-analysis": "jsa",
  "permit-to-work": "permitToWork",
  "hazop": "hazop",
  "hazop-study": "hazop",
  "minutes-of-meeting": "minutesOfMeeting",
  "sds": "sds",
};

/**
 * Maps NordSafe record types (controllers) to SharePoint list display names.
 */
const LIST_MAP = {
  "deviations": "NordSafe_Deviations",
  "case-investigations": "NordSafe_Incidents",
  "site-monitoring": "NordSafe_SiteMonitoring",
  "job-safety-analysis": "NordSafe_JSA",
  "toolbox-meeting": "NordSafe_ToolboxMeetings",
  "pre-task-checklist": "NordSafe_Checklists",
  "equipment-controller": "NordSafe_Equipment",
  "risk-assessment": "NordSafe_RiskAssessments",
  "permit-to-work": "NordSafe_PTW",
  "hazop": "NordSafe_HAZOP",
  "hazop-study": "NordSafe_HAZOP",
  "sds": "NordSafe_SDS",
  "entrance-log": "NordSafe_EntranceLog",
  "minutes-of-meeting": "NordSafe_MinutesOfMeeting",
  "training": "NordSafe_Training",
};

/**
 * One-time provisioning: create standard NordSafe lists on a specific SharePoint site.
 * Uses delegated token first, falls back to app-only token if permission denied.
 * 
 * @param {number} companyId - The company ID
 * @param {string} accessToken - Microsoft Graph access token (delegated)
 * @param {boolean} forceRecreate - If true, will attempt to create missing lists even if some exist
 * @param {boolean} useAppOnly - If true, uses app-only authentication instead of delegated
 * @param {string} customSiteUrl - Optional: Custom site URL (e.g., "sites/NordSafe" or "sites/CustomerName")
 * @returns {Promise<Object>} Setup result with success status, lists created, and any errors
 */
const setupCompanySharepoint = async (companyId, accessToken, forceRecreate = false, useAppOnly = false, customSiteUrl = null) => {
  try {
    console.log(`🔧 Starting SharePoint setup for company ${companyId}...`);
    
    // If useAppOnly is true, get app-only token
    let token = accessToken;
    if (useAppOnly) {
      console.log("🔑 Using app-only authentication (application permissions)");
      token = await getAppOnlyAccessToken();
    }
    
    // Get site ID - use custom site if provided, otherwise use root
    let siteId;
    if (customSiteUrl) {
      console.log(`📍 Using custom site: ${customSiteUrl}`);
      // Get specific site by URL path
      const siteResponse = await fetch(`https://graph.microsoft.com/v1.0/${customSiteUrl}`, {
        headers: { Authorization: `Bearer ${token}` }
      });
      if (siteResponse.ok) {
        const site = await siteResponse.json();
        siteId = site.id;
      } else {
        console.error(`❌ Cannot access custom site: ${customSiteUrl}`);
        return { success: false, error: `Cannot access site: ${customSiteUrl}` };
      }
    } else {
      siteId = await getSiteId(token);
    }
    
    if (!siteId) {
      console.error('❌ Cannot reach SharePoint / Graph sites');
      return { success: false, error: "Cannot reach SharePoint / Graph sites" };
    }

    console.log(`✅ SharePoint site ID obtained: ${siteId}`);

    // First check what lists already exist
    let existingLists = [];
    try {
      existingLists = await getLists(token, siteId);
      console.log(`📋 Found ${existingLists.length} existing lists`);
    } catch (e) {
      console.log('⚠️  Could not fetch existing lists:', e.message);
    }
    const existingNames = existingLists.map(l => l.name);

    const listConfigs = [
      {
        name: "NordSafe_Deviations",
        columns: [
          { name: "Title", type: "text" },
          { name: "Status", type: "text" },
          { name: "Severity", type: "text" },
          { name: "Location", type: "text" },
          { name: "Description", type: "note" },
          { name: "NordSafeId", type: "text" },
          { name: "ReportedBy", type: "text" },
          { name: "DeviationDate", type: "dateTime" },
          { name: "ProjectId", type: "text" },
          { name: "ActionTaken", type: "note" },
          { name: "RootCause", type: "note" },
        ],
      },
      {
        name: "NordSafe_SiteMonitoring",
        columns: [
          { name: "Title", type: "text" },
          { name: "Status", type: "text" },
          { name: "RiskLevel", type: "text" },
          { name: "Location", type: "text" },
          { name: "Description", type: "note" },
          { name: "NordSafeId", type: "text" },
          { name: "MonitoredBy", type: "text" },
          { name: "MonitoringDate", type: "dateTime" },
          { name: "ProjectId", type: "text" },
          { name: "CorrectiveAction", type: "note" },
          { name: "Priority", type: "text" },
        ],
      },
      {
        name: "NordSafe_Incidents",
        columns: [
          { name: "Title", type: "text" },
          { name: "Status", type: "text" },
          { name: "Severity", type: "text" },
          { name: "Location", type: "text" },
          { name: "Description", type: "note" },
          { name: "NordSafeId", type: "text" },
          { name: "ReportedBy", type: "text" },
          { name: "IncidentDate", type: "dateTime" },
          { name: "ProjectId", type: "text" },
        ],
      },
      {
        name: "NordSafe_RiskAssessments",
        columns: [
          { name: "Title", type: "text" },
          { name: "Status", type: "text" },
          { name: "RiskLevel", type: "text" },
          { name: "Location", type: "text" },
          { name: "NordSafeId", type: "text" },
          { name: "AssessedBy", type: "text" },
          { name: "ReviewDate", type: "date" },
          { name: "ProjectId", type: "text" },
        ],
      },
      {
        name: "NordSafe_JSA",
        columns: [
          { name: "Title", type: "text" },
          { name: "Status", type: "text" },
          { name: "TaskActivity", type: "text" },
          { name: "NordSafeId", type: "text" },
          { name: "PreparedBy", type: "text" },
          { name: "ProjectId", type: "text" },
        ],
      },
      {
        name: "NordSafe_PTW",
        columns: [
          { name: "Title", type: "text" },
          { name: "Status", type: "text" },
          { name: "PermitType", type: "text" },
          { name: "Location", type: "text" },
          { name: "NordSafeId", type: "text" },
          { name: "RequestedBy", type: "text" },
          { name: "ValidUntil", type: "dateTime" },
          { name: "ProjectId", type: "text" },
        ],
      },
      {
        name: "NordSafe_HAZOP",
        columns: [
          { name: "Title", type: "text" },
          { name: "Status", type: "text" },
          { name: "StudyType", type: "text" },
          { name: "ProcessUnit", type: "text" },
          { name: "NordSafeId", type: "text" },
          { name: "LeadUser", type: "text" },
          { name: "ProjectId", type: "text" },
          { name: "StudyData", type: "note" },
        ],
      },
      {
        name: "NordSafe_SDS",
        columns: [
          { name: "Title", type: "text" },
          { name: "ProductName", type: "text" },
          { name: "NordSafeId", type: "text" },
          { name: "Supplier", type: "text" },
          { name: "RevisionDate", type: "date" },
          { name: "ProjectId", type: "text" },
        ],
      },
      {
        name: "NordSafe_MinutesOfMeeting",
        columns: [
          { name: "Title", type: "text" },
          { name: "MeetingDate", type: "dateTime" },
          { name: "Location", type: "text" },
          { name: "NordSafeId", type: "text" },
          { name: "Chairperson", type: "text" },
          { name: "Attendees", type: "note" },
          { name: "ProjectId", type: "text" },
        ],
      },
      {
        name: "NordSafe_Training",
        columns: [
          { name: "Title", type: "text" },
          { name: "VideoTitle", type: "text" },
          { name: "NordSafeId", type: "text" },
          { name: "UserEmail", type: "text" },
          { name: "Status", type: "text" },
          { name: "Score", type: "number" },
          { name: "CertificateId", type: "text" },
          { name: "CompletedAt", type: "dateTime" },
        ],
      },
    ];

    const results = {};
    const createdLists = [];
    const failedLists = [];
    let creationBlocked = false;

    for (const config of listConfigs) {
      // Skip if list already exists (unless forceRecreate is true)
      if (existingNames.includes(config.name) && !forceRecreate) {
        console.log(`⏭️  List already exists: ${config.name}`);
        const existing = existingLists.find(l => l.name === config.name);
        if (existing) results[config.name] = existing.id;
        continue;
      }

      try {
        const created = await createList(token, siteId, config.name, config.columns);
        results[config.name] = created.id;
        createdLists.push(config.name);
        console.log(`✅ SharePoint List created: ${config.name}`);
      } catch (e) {
        if (e.response?.status === 403 || e.message?.includes('403')) {
          creationBlocked = true;
          const errorDetail = e.response?.data?.error?.message || e.message;
          failedLists.push({ name: config.name, reason: 'Permission denied (403)', detail: errorDetail });
          console.log(`⚠️  Cannot auto-create list (permission): ${config.name}`);
          console.log(`   Error detail: ${errorDetail}`);
        } else {
          failedLists.push({ name: config.name, reason: e.message });
          console.log(`⚠️  Failed to create list: ${config.name} — ${e.message}`);
        }
      }
    }

    // If creation was blocked and we haven't tried app-only yet, retry with app-only
    if (creationBlocked && !useAppOnly && failedLists.length > 0) {
      console.log("\n🔄 Delegated permissions failed. Retrying with app-only authentication...\n");
      return await setupCompanySharepoint(companyId, accessToken, forceRecreate, true);
    }

    // Re-fetch all lists to build the mapping (includes manually created ones)
    const allLists = await getLists(accessToken, siteId);
    const spListMapping = {};
    for (const l of allLists) {
      const mod = LIST_DISPLAY_TO_MODULE[l.name];
      if (mod) spListMapping[mod] = l.id;
    }

    await Companies.update(
      { msSharepointSiteId: siteId, msConnected: true, spListMapping },
      { where: { id: companyId } },
    );

    const missingLists = listConfigs
      .map(c => c.name)
      .filter(name => !allLists.find(l => l.name === name));

    console.log(`✅ SharePoint setup completed for company ${companyId}`);
    console.log(`   - Created: ${createdLists.length} lists`);
    console.log(`   - Failed: ${failedLists.length} lists`);
    console.log(`   - Missing: ${missingLists.length} lists`);

    return {
      success: true,
      siteId,
      lists: results,
      spListMapping,
      createdLists,
      failedLists,
      creationBlocked,
      missingLists,
      message: createdLists.length > 0 
        ? `Successfully created ${createdLists.length} SharePoint lists automatically`
        : missingLists.length > 0
        ? `SharePoint connected but ${missingLists.length} lists need to be created manually`
        : 'All SharePoint lists already exist',
    };
  } catch (err) {
    console.error("❌ SharePoint setup failed:", err.message);
    return { success: false, error: err.message };
  }
};

const syncToSharepoint = async ({ companyId, recordType, recordId, fields }) => {
  try {
    const company = await Companies.findByPk(companyId);
    if (!company?.msConnected || !company?.msSharepointSiteId) return;

    const accessToken = await ensureFreshMsAccessToken(companyId);
    if (!accessToken) return;

    const mapping = company.spListMapping || {};
    const moduleKey = RECORD_TYPE_TO_MODULE_KEY[recordType];
    let listId = moduleKey ? mapping[moduleKey] : null;

    const listName = LIST_MAP[recordType];
    if (!listId && listName) {
      const lists = await getLists(accessToken, company.msSharepointSiteId);
      const list = lists.find((l) => l.name === listName);
      listId = list?.id;
    }
    if (!listId) return;

    await createItem(accessToken, company.msSharepointSiteId, listId, {
      ...fields,
      NordSafeId: recordId.toString(),
    });

    console.log(`✅ Synced to SharePoint — ${recordType} ID ${recordId}`);
  } catch (err) {
    console.error(`SharePoint sync failed for ${recordType}:`, err.message);
  }
};

module.exports = {
  setupCompanySharepoint,
  syncToSharepoint,
  LIST_MAP,
  LIST_DISPLAY_TO_MODULE,
  RECORD_TYPE_TO_MODULE_KEY,
};
