import { DataTypes, Model, Optional } from 'sequelize';
import { sequelize } from '../config/database';
// ApiToken association is defined in ApiToken.ts to avoid circular dependency issues
// but we can declare the mixin type here if needed.


/**
 * User Role Enum
 * 
 * USER: Default role - can create requests, view own requests, participate in workflows
 * MANAGEMENT: Enhanced visibility - can view all requests, read-only access to all data
 * ADMIN: Full access - can manage system configuration, users, and all workflows
 */
export type UserRole = 'USER' | 'MANAGEMENT' | 'ADMIN';

interface UserAttributes {
  userId: string;
  employeeId?: string | null;
  oktaSub: string;
  email: string;
  firstName?: string | null;
  lastName?: string | null;
  displayName?: string | null;
  department?: string | null;
  designation?: string | null;
  phone?: string | null;

  // Extended fields from SSO/Okta (All Optional)
  manager?: string | null; // Reporting manager name
  secondEmail?: string | null; // Alternate email
  jobTitle?: string | null; // Detailed job description (title field from Okta)
  employeeNumber?: string | null; // HR system employee number (different from employeeId)
  postalAddress?: string | null; // Work location/office address
  mobilePhone?: string | null; // Mobile contact (different from phone)
  adGroups?: string[] | null; // Active Directory group memberships

  // Location Information (JSON object)
  location?: {
    city?: string;
    state?: string;
    country?: string;
    office?: string;
    timezone?: string;
  };

  // Notification Preferences
  emailNotificationsEnabled: boolean;
  pushNotificationsEnabled: boolean;
  inAppNotificationsEnabled: boolean;

  isActive: boolean;
  role: UserRole; // RBAC: USER, MANAGEMENT, ADMIN
  lastLogin?: Date;
  sessionToken?: string | null;
  lastLoginDevice?: string | null;
  createdAt: Date;
  updatedAt: Date;
}

interface UserCreationAttributes extends Optional<UserAttributes, 'userId' | 'employeeId' | 'department' | 'designation' | 'phone' | 'manager' | 'secondEmail' | 'jobTitle' | 'employeeNumber' | 'postalAddress' | 'mobilePhone' | 'adGroups' | 'emailNotificationsEnabled' | 'pushNotificationsEnabled' | 'inAppNotificationsEnabled' | 'role' | 'lastLogin' | 'sessionToken' | 'lastLoginDevice' | 'createdAt' | 'updatedAt'> { }

class User extends Model<UserAttributes, UserCreationAttributes> implements UserAttributes {
  public userId!: string;
  public employeeId?: string | null;
  public oktaSub!: string;
  public email!: string;
  public firstName?: string | null;
  public lastName?: string | null;
  public displayName?: string | null;
  public department?: string;
  public designation?: string;
  public phone?: string;

  // Extended fields from SSO/Okta (All Optional)
  public manager?: string | null;
  public secondEmail?: string | null;
  public jobTitle?: string | null;
  public employeeNumber?: string | null;
  public postalAddress?: string | null;
  public mobilePhone?: string | null;
  public adGroups?: string[] | null;

  // Location Information (JSON object)
  public location?: {
    city?: string;
    state?: string;
    country?: string;
    office?: string;
    timezone?: string;
  };

  // Notification Preferences
  public emailNotificationsEnabled!: boolean;
  public pushNotificationsEnabled!: boolean;
  public inAppNotificationsEnabled!: boolean;

  public isActive!: boolean;
  public role!: UserRole; // RBAC: USER, MANAGEMENT, ADMIN
  public lastLogin?: Date;
  public sessionToken?: string | null;
  public lastLoginDevice?: string | null;
  public createdAt!: Date;
  public updatedAt!: Date;

  // Associations

  /**
   * Helper Methods for Role Checking
   */
  public isUserRole(): boolean {
    return this.role === 'USER';
  }

  public isManagementRole(): boolean {
    return this.role === 'MANAGEMENT';
  }

  public isAdminRole(): boolean {
    return this.role === 'ADMIN';
  }

  public hasManagementAccess(): boolean {
    return this.role === 'MANAGEMENT' || this.role === 'ADMIN';
  }

  public hasAdminAccess(): boolean {
    return this.role === 'ADMIN';
  }
}

User.init(
  {
    userId: {
      type: DataTypes.UUID,
      defaultValue: DataTypes.UUIDV4,
      primaryKey: true,
      field: 'user_id'
    },
    employeeId: {
      type: DataTypes.STRING(50),
      allowNull: true, // Made optional - email is now primary identifier
      field: 'employee_id',
      comment: 'HR System Employee ID (optional)'
    },
    oktaSub: {
      type: DataTypes.STRING(100),
      allowNull: false,
      unique: true,
      field: 'okta_sub',
      comment: 'Okta user sub (subject identifier) - unique identifier from Okta'
    },
    email: {
      type: DataTypes.STRING(255),
      allowNull: false,
      unique: true,
      validate: {
        isEmail: true
      }
    },
    firstName: {
      type: DataTypes.STRING(100),
      allowNull: true, // Made optional - can be derived from displayName if needed
      defaultValue: '',
      field: 'first_name'
    },
    lastName: {
      type: DataTypes.STRING(100),
      allowNull: true, // Made optional - can be derived from displayName if needed
      defaultValue: '',
      field: 'last_name'
    },
    displayName: {
      type: DataTypes.STRING(200),
      allowNull: true, // Made optional - can be generated from firstName + lastName if needed
      defaultValue: '',
      field: 'display_name',
      comment: 'Full Name for display'
    },
    department: {
      type: DataTypes.STRING(100),
      allowNull: true
    },
    designation: {
      type: DataTypes.STRING(100),
      allowNull: true
    },
    phone: {
      type: DataTypes.STRING(20),
      allowNull: true
    },

    // ============ Extended SSO/Okta Fields (All Optional) ============
    manager: {
      type: DataTypes.STRING(200),
      allowNull: true,
      comment: 'Reporting manager name from SSO/AD'
    },
    secondEmail: {
      type: DataTypes.STRING(255),
      allowNull: true,
      field: 'second_email',
      validate: {
        isEmail: true
      },
      comment: 'Alternate email address from SSO'
    },
    jobTitle: {
      type: DataTypes.TEXT,
      allowNull: true,
      field: 'job_title',
      comment: 'Detailed job title/description from SSO (e.g., "Manages dealers for MotorCycle Business...")'
    },
    employeeNumber: {
      type: DataTypes.STRING(50),
      allowNull: true,
      field: 'employee_number',
      comment: 'HR system employee number from SSO (e.g., "00020330")'
    },
    postalAddress: {
      type: DataTypes.STRING(500),
      allowNull: true,
      field: 'postal_address',
      comment: 'Work location/office address from SSO (e.g., "Kolkata", "Chennai")'
    },
    mobilePhone: {
      type: DataTypes.STRING(20),
      allowNull: true,
      field: 'mobile_phone',
      comment: 'Mobile contact number from SSO (mobilePhone field)'
    },
    adGroups: {
      type: DataTypes.JSONB,
      allowNull: true,
      field: 'ad_groups',
      comment: 'Active Directory group memberships from SSO (memberOf field) - JSON array'
    },

    // Location Information (JSON object)
    location: {
      type: DataTypes.JSONB, // Use JSONB for PostgreSQL
      allowNull: true,
      comment: 'JSON object containing location details (city, state, country, office, timezone)'
    },

    // Notification Preferences
    emailNotificationsEnabled: {
      type: DataTypes.BOOLEAN,
      allowNull: false,
      defaultValue: true,
      field: 'email_notifications_enabled',
      comment: 'User preference for receiving email notifications'
    },
    pushNotificationsEnabled: {
      type: DataTypes.BOOLEAN,
      allowNull: false,
      defaultValue: true,
      field: 'push_notifications_enabled',
      comment: 'User preference for receiving push notifications'
    },
    inAppNotificationsEnabled: {
      type: DataTypes.BOOLEAN,
      allowNull: false,
      defaultValue: true,
      field: 'in_app_notifications_enabled',
      comment: 'User preference for receiving in-app notifications'
    },

    isActive: {
      type: DataTypes.BOOLEAN,
      defaultValue: true,
      field: 'is_active',
      comment: 'Account status'
    },
    role: {
      type: DataTypes.ENUM('USER', 'MANAGEMENT', 'ADMIN'),
      allowNull: false,
      defaultValue: 'USER',
      comment: 'User role for access control: USER (default), MANAGEMENT (read all), ADMIN (full access)'
    },
    lastLogin: {
      type: DataTypes.DATE,
      allowNull: true,
      field: 'last_login'
    },
    sessionToken: {
      type: DataTypes.UUID,
      allowNull: true,
      field: 'sessionToken',
      comment: 'Unique token for active session to restrict concurrent logins'
    },
    lastLoginDevice: {
      type: DataTypes.STRING(255),
      allowNull: true,
      field: 'lastLoginDevice',
      comment: 'Browser/Device string from User-Agent of the active session'
    },
    createdAt: {
      type: DataTypes.DATE,
      allowNull: false,
      defaultValue: DataTypes.NOW,
      field: 'created_at'
    },
    updatedAt: {
      type: DataTypes.DATE,
      allowNull: false,
      defaultValue: DataTypes.NOW,
      field: 'updated_at'
    }
  },
  {
    sequelize,
    modelName: 'User',
    tableName: 'users',
    timestamps: true,
    createdAt: 'created_at',
    updatedAt: 'updated_at',
    indexes: [
      {
        unique: true,
        fields: ['okta_sub']
      },
      {
        unique: true,
        fields: ['email']
      },
      {
        fields: ['employee_id'] // Non-unique index for employee_id (now optional)
      },
      {
        fields: ['department']
      },
      {
        fields: ['is_active']
      },
      {
        fields: ['role'], // Index for role-based queries
        name: 'idx_users_role'
      },
      {
        fields: ['manager'], // Index for org chart queries
        name: 'idx_users_manager'
      },
      {
        fields: ['postal_address'], // Index for location-based filtering
        name: 'idx_users_postal_address'
      },
      {
        fields: ['location'],
        using: 'gin', // GIN index for JSONB queries
        operator: 'jsonb_path_ops'
      }
      // Note: ad_groups GIN index is created in migration (can't be defined here)
    ]
  }
);

export { User };
